summaryrefslogtreecommitdiffstats
path: root/arts
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commite2de64d6f1beb9e492daf5b886e19933c1fa41dd (patch)
tree9047cf9e6b5c43878d5bf82660adae77ceee097a /arts
downloadtdemultimedia-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')
-rw-r--r--arts/Makefile.am9
-rw-r--r--arts/builder/FullDuplexTest.arts139
-rw-r--r--arts/builder/Makefile.am39
-rw-r--r--arts/builder/TODO69
-rw-r--r--arts/builder/artsbuilder.desktop122
-rw-r--r--arts/builder/artsbuilderui.rc47
-rw-r--r--arts/builder/autorouter.cpp609
-rw-r--r--arts/builder/autorouter.h184
-rw-r--r--arts/builder/createtool.cpp339
-rw-r--r--arts/builder/createtool.h132
-rw-r--r--arts/builder/dirmanager.cpp96
-rw-r--r--arts/builder/dirmanager.h34
-rw-r--r--arts/builder/drawutils.cpp39
-rw-r--r--arts/builder/drawutils.h31
-rw-r--r--arts/builder/execdlg.cpp201
-rw-r--r--arts/builder/execdlg.h54
-rw-r--r--arts/builder/interfacedlg.cpp178
-rw-r--r--arts/builder/interfacedlg.h52
-rw-r--r--arts/builder/main.cpp958
-rw-r--r--arts/builder/main.h118
-rw-r--r--arts/builder/menumaker.cpp212
-rw-r--r--arts/builder/menumaker.h70
-rw-r--r--arts/builder/module.cpp439
-rw-r--r--arts/builder/module.h108
-rw-r--r--arts/builder/mwidget.cpp652
-rw-r--r--arts/builder/mwidget.h129
-rw-r--r--arts/builder/pics/Makefile.am24
-rw-r--r--arts/builder/pics/Synth_ADD.xpm305
-rw-r--r--arts/builder/pics/Synth_AMAN_PLAY.xpm316
-rw-r--r--arts/builder/pics/Synth_ATAN_SATURATE.xpm310
-rw-r--r--arts/builder/pics/Synth_AUTOPANNER.xpm292
-rw-r--r--arts/builder/pics/Synth_BUS_DOWNLINK.xpm323
-rw-r--r--arts/builder/pics/Synth_BUS_UPLINK.xpm323
-rw-r--r--arts/builder/pics/Synth_DEBUG.xpm319
-rw-r--r--arts/builder/pics/Synth_DIV.xpm1350
-rw-r--r--arts/builder/pics/Synth_EMPTY.xpm1119
-rw-r--r--arts/builder/pics/Synth_ENVELOPE_ADSR.xpm318
-rw-r--r--arts/builder/pics/Synth_FILEPLAY.xpm312
-rw-r--r--arts/builder/pics/Synth_MIDI_DEBUG.xpm323
-rw-r--r--arts/builder/pics/Synth_MIDI_ROUTER.xpm323
-rw-r--r--arts/builder/pics/Synth_MOOG_VCF.xpm305
-rw-r--r--arts/builder/pics/Synth_MUL.xpm309
-rw-r--r--arts/builder/pics/Synth_MULTI_ADD.xpm1510
-rw-r--r--arts/builder/pics/Synth_PLAY.xpm316
-rw-r--r--arts/builder/pics/Synth_PLAY_AKAI.xpm317
-rw-r--r--arts/builder/pics/Synth_PLAY_AKAIS.xpm317
-rw-r--r--arts/builder/pics/Synth_PLAY_WAV.xpm317
-rw-r--r--arts/builder/pics/Synth_PSCALE.xpm299
-rw-r--r--arts/builder/pics/Synth_RC.xpm323
-rw-r--r--arts/builder/pics/Synth_SEQUENCE.xpm319
-rw-r--r--arts/builder/pics/Synth_SEQUENCE_FREQ.pngbin0 -> 3545 bytes
-rw-r--r--arts/builder/pics/Synth_SHELVE_CUTOFF.xpm247
-rw-r--r--arts/builder/pics/Synth_WAVE_SAW.xpm323
-rw-r--r--arts/builder/pics/Synth_WAVE_SIN.xpm320
-rw-r--r--arts/builder/pics/Synth_WAVE_SQUARE.xpm323
-rw-r--r--arts/builder/pics/Synth_WAVE_TRI.xpm305
-rw-r--r--arts/builder/pics/Synth_XFADE.xpm313
-rw-r--r--arts/builder/pics/cr16-action-artsbuilderexecute.pngbin0 -> 133 bytes
-rw-r--r--arts/builder/pics/cr22-action-artsbuilderexecute.pngbin0 -> 184 bytes
-rw-r--r--arts/builder/pics/hi16-app-artsbuilder.pngbin0 -> 898 bytes
-rw-r--r--arts/builder/pics/hi16-app-artscontrol.pngbin0 -> 859 bytes
-rw-r--r--arts/builder/pics/hisc-app-artsbuilder.svgzbin0 -> 1971 bytes
-rw-r--r--arts/builder/pics/hisc-app-artscontrol.svgzbin0 -> 4421 bytes
-rw-r--r--arts/builder/portposdlg.cpp258
-rw-r--r--arts/builder/portposdlg.h51
-rw-r--r--arts/builder/propertypanel.cpp404
-rw-r--r--arts/builder/propertypanel.h78
-rw-r--r--arts/builder/propertypanelbase.ui362
-rw-r--r--arts/builder/qttableview.cpp2274
-rw-r--r--arts/builder/qttableview.h251
-rw-r--r--arts/builder/retrievedlg.cpp137
-rw-r--r--arts/builder/retrievedlg.h45
-rw-r--r--arts/builder/scomponent.cpp108
-rw-r--r--arts/builder/scomponent.h87
-rw-r--r--arts/builder/session.cpp80
-rw-r--r--arts/builder/session.h38
-rw-r--r--arts/builder/structure.cpp462
-rw-r--r--arts/builder/structure.h92
-rw-r--r--arts/builder/structureport.cpp287
-rw-r--r--arts/builder/structureport.h66
-rw-r--r--arts/builder/x-artsbuilder.desktop60
-rw-r--r--arts/configure.in.in60
-rw-r--r--arts/examples/Makefile.am73
-rw-r--r--arts/examples/README256
-rw-r--r--arts/examples/TODO2
-rwxr-xr-xarts/examples/checknames.sh9
-rw-r--r--arts/examples/effect_delay.arts310
-rw-r--r--arts/examples/effect_delay_alone.arts310
-rw-r--r--arts/examples/effect_flanger_alone.arts285
-rw-r--r--arts/examples/example_adsr.arts137
-rw-r--r--arts/examples/example_atan_saturate.arts81
-rw-r--r--arts/examples/example_autopanner.arts117
-rw-r--r--arts/examples/example_brickwall.arts98
-rw-r--r--arts/examples/example_bus.arts44
-rw-r--r--arts/examples/example_capture_wav.arts50
-rw-r--r--arts/examples/example_cdelay.arts64
-rw-r--r--arts/examples/example_cflanger.arts127
-rw-r--r--arts/examples/example_data.arts39
-rw-r--r--arts/examples/example_delay.arts65
-rw-r--r--arts/examples/example_dtmf1.arts155
-rw-r--r--arts/examples/example_equalizer.arts84
-rw-r--r--arts/examples/example_fm.arts102
-rw-r--r--arts/examples/example_freeverb.arts99
-rw-r--r--arts/examples/example_moog.arts96
-rw-r--r--arts/examples/example_multi_add.arts83
-rw-r--r--arts/examples/example_noise.arts39
-rw-r--r--arts/examples/example_pitchshift.arts69
-rw-r--r--arts/examples/example_play_wave.arts57
-rw-r--r--arts/examples/example_pscale.arts112
-rw-r--r--arts/examples/example_pulse.arts66
-rw-r--r--arts/examples/example_rc.arts63
-rw-r--r--arts/examples/example_record.arts75
-rw-r--r--arts/examples/example_sequence.arts85
-rw-r--r--arts/examples/example_shelve_cutoff.arts61
-rw-r--r--arts/examples/example_sine.arts58
-rw-r--r--arts/examples/example_softsaw.arts61
-rw-r--r--arts/examples/example_square.arts61
-rw-r--r--arts/examples/example_stereobeep.arts91
-rw-r--r--arts/examples/example_tremolo.arts118
-rw-r--r--arts/examples/example_tri.arts61
-rw-r--r--arts/examples/example_xfade.arts120
-rw-r--r--arts/examples/instrument_arts_all.arts-map14
-rw-r--r--arts/examples/instrument_chirpdrum.arts260
-rw-r--r--arts/examples/instrument_deepdrum.arts255
-rw-r--r--arts/examples/instrument_flexible_slide.arts537
-rw-r--r--arts/examples/instrument_flexible_slide_GUI.arts481
-rw-r--r--arts/examples/instrument_fm_horn.arts301
-rw-r--r--arts/examples/instrument_full_square.arts422
-rw-r--r--arts/examples/instrument_hihat.arts235
-rw-r--r--arts/examples/instrument_moog_vcf_tune.arts341
-rw-r--r--arts/examples/instrument_moog_vcf_tune_GUI.arts331
-rw-r--r--arts/examples/instrument_neworgan.arts532
-rw-r--r--arts/examples/instrument_nokind.arts503
-rw-r--r--arts/examples/instrument_organ2.arts532
-rw-r--r--arts/examples/instrument_simple_sin.arts190
-rw-r--r--arts/examples/instrument_simple_square.arts190
-rw-r--r--arts/examples/instrument_simple_tri.arts304
-rw-r--r--arts/examples/instrument_slide.arts464
-rw-r--r--arts/examples/instrument_slide1.arts467
-rw-r--r--arts/examples/instrument_square.arts465
-rw-r--r--arts/examples/instrument_tri.arts348
-rw-r--r--arts/examples/mixer_element_eq.arts567
-rw-r--r--arts/examples/mixer_element_eqfx.arts740
-rw-r--r--arts/examples/mixer_element_simple.arts235
-rw-r--r--arts/examples/template_Empty_Structure.arts1
-rw-r--r--arts/examples/template_Instrument.arts103
-rw-r--r--arts/examples/template_Instrument_GUI.arts91
-rw-r--r--arts/examples/template_Mixer_Element.arts176
-rw-r--r--arts/gui/Makefile.am7
-rw-r--r--arts/gui/common/GenericGuiFactory.mcopclass3
-rw-r--r--arts/gui/common/Makefile.am35
-rw-r--r--arts/gui/common/artsgui.idl396
-rw-r--r--arts/gui/common/genericguifactory_impl.cc56
-rw-r--r--arts/gui/kde/Makefile.am38
-rw-r--r--arts/gui/kde/artstestgui.cpp124
-rw-r--r--arts/gui/kde/dbtest.cpp42
-rw-r--r--arts/gui/kde/dbtest.h16
-rw-r--r--arts/gui/kde/dbvolcalc.h82
-rw-r--r--arts/gui/kde/kartswidget.cpp89
-rw-r--r--arts/gui/kde/kartswidget.h92
-rw-r--r--arts/gui/kde/kbutton_impl.cpp135
-rw-r--r--arts/gui/kde/kbutton_impl.h76
-rw-r--r--arts/gui/kde/kcombobox_impl.cpp105
-rw-r--r--arts/gui/kde/kcombobox_impl.h74
-rw-r--r--arts/gui/kde/kfader.cpp31
-rw-r--r--arts/gui/kde/kfader.h46
-rw-r--r--arts/gui/kde/kfader_impl.cpp206
-rw-r--r--arts/gui/kde/kfader_impl.h92
-rw-r--r--arts/gui/kde/kframe_impl.cpp98
-rw-r--r--arts/gui/kde/kframe_impl.h55
-rw-r--r--arts/gui/kde/kgraph.cpp266
-rw-r--r--arts/gui/kde/kgraph.h64
-rw-r--r--arts/gui/kde/kgraph_impl.cpp92
-rw-r--r--arts/gui/kde/kgraph_impl.h65
-rw-r--r--arts/gui/kde/kgraphline_impl.cpp124
-rw-r--r--arts/gui/kde/kgraphline_impl.h61
-rw-r--r--arts/gui/kde/khbox_impl.cpp51
-rw-r--r--arts/gui/kde/khbox_impl.h48
-rw-r--r--arts/gui/kde/klabel_impl.cpp104
-rw-r--r--arts/gui/kde/klabel_impl.h90
-rw-r--r--arts/gui/kde/klayoutbox_impl.cpp122
-rw-r--r--arts/gui/kde/klayoutbox_impl.h103
-rw-r--r--arts/gui/kde/klevelmeter_firebars.cpp125
-rw-r--r--arts/gui/kde/klevelmeter_firebars.h58
-rw-r--r--arts/gui/kde/klevelmeter_impl.cpp131
-rw-r--r--arts/gui/kde/klevelmeter_impl.h70
-rw-r--r--arts/gui/kde/klevelmeter_linebars.cpp109
-rw-r--r--arts/gui/kde/klevelmeter_linebars.h46
-rw-r--r--arts/gui/kde/klevelmeter_normalbars.cpp81
-rw-r--r--arts/gui/kde/klevelmeter_normalbars.h75
-rw-r--r--arts/gui/kde/klevelmeter_private.h55
-rw-r--r--arts/gui/kde/klevelmeter_small.cpp59
-rw-r--r--arts/gui/kde/klevelmeter_small.h39
-rw-r--r--arts/gui/kde/klevelmeter_template.h70
-rw-r--r--arts/gui/kde/klineedit_impl.cpp75
-rw-r--r--arts/gui/kde/klineedit_impl.h63
-rw-r--r--arts/gui/kde/kpopupbox_impl.cpp134
-rw-r--r--arts/gui/kde/kpopupbox_impl.h70
-rw-r--r--arts/gui/kde/kpopupbox_private.h216
-rw-r--r--arts/gui/kde/kpoti.cpp780
-rw-r--r--arts/gui/kde/kpoti.h136
-rw-r--r--arts/gui/kde/kpoti_impl.cpp203
-rw-r--r--arts/gui/kde/kpoti_impl.h90
-rw-r--r--arts/gui/kde/kspinbox_impl.cpp108
-rw-r--r--arts/gui/kde/kspinbox_impl.h76
-rw-r--r--arts/gui/kde/ktickmarks_impl.cpp179
-rw-r--r--arts/gui/kde/ktickmarks_impl.h76
-rw-r--r--arts/gui/kde/kvbox_impl.cpp51
-rw-r--r--arts/gui/kde/kvbox_impl.h48
-rw-r--r--arts/gui/kde/kvolumefader_impl.cpp243
-rw-r--r--arts/gui/kde/kvolumefader_impl.h97
-rw-r--r--arts/gui/kde/kwidget_impl.cpp181
-rw-r--r--arts/gui/kde/kwidget_impl.h88
-rw-r--r--arts/gui/kde/kwidgetrepo.cpp89
-rw-r--r--arts/gui/kde/kwidgetrepo.h56
-rw-r--r--arts/gui/kde/mcopclass/Button.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/Fader.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/Graph.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/GraphLine.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/HBox.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/Label.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/LayoutBox.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/LevelMeter.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/LineEdit.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/Makefile.am5
-rw-r--r--arts/gui/kde/mcopclass/PopupBox.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/Poti.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/SpinBox.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/VBox.mcopclass5
-rw-r--r--arts/gui/kde/mcopclass/Widget.mcopclass5
-rw-r--r--arts/midi/Makefile.am53
-rw-r--r--arts/midi/README.midi261
-rw-r--r--arts/midi/alsamidigateway_impl.cc243
-rw-r--r--arts/midi/alsamidiport_impl.cc232
-rw-r--r--arts/midi/alsamidiport_impl.h85
-rw-r--r--arts/midi/artsmidi.idl379
-rw-r--r--arts/midi/audiomiditimer_impl.cc116
-rw-r--r--arts/midi/audiosync_impl.cc203
-rw-r--r--arts/midi/audiosync_impl.h79
-rw-r--r--arts/midi/audiotimer.cc98
-rw-r--r--arts/midi/audiotimer.h73
-rw-r--r--arts/midi/mcopclass/Makefile.am2
-rw-r--r--arts/midi/mcopclass/MidiManager.mcopclass3
-rw-r--r--arts/midi/midiclient_impl.cc274
-rw-r--r--arts/midi/midiclient_impl.h80
-rw-r--r--arts/midi/midimanager_impl.cc156
-rw-r--r--arts/midi/midimanager_impl.h67
-rw-r--r--arts/midi/midimanagerport_impl.cc71
-rw-r--r--arts/midi/midimanagerport_impl.h46
-rw-r--r--arts/midi/midimsg.c177
-rw-r--r--arts/midi/midimsg.h44
-rw-r--r--arts/midi/midisend.cc375
-rw-r--r--arts/midi/midisend.h106
-rw-r--r--arts/midi/midisyncgroup_impl.cc125
-rw-r--r--arts/midi/midisyncgroup_impl.h67
-rw-r--r--arts/midi/midisynctest.cc137
-rw-r--r--arts/midi/miditest_impl.cc57
-rw-r--r--arts/midi/miditimercommon.cc72
-rw-r--r--arts/midi/miditimercommon.h59
-rw-r--r--arts/midi/rawmidiport_impl.cc306
-rw-r--r--arts/midi/systemmiditimer_impl.cc105
-rw-r--r--arts/midi/timestampmath.cc112
-rw-r--r--arts/midi/timestampmath.h62
-rw-r--r--arts/modules/Makefile.am60
-rw-r--r--arts/modules/README.environments304
-rw-r--r--arts/modules/README.modules28
-rw-r--r--arts/modules/README.subdirs18
-rw-r--r--arts/modules/TODO58
-rw-r--r--arts/modules/artsmodules.idl186
-rw-r--r--arts/modules/common/Makefile.am61
-rw-r--r--arts/modules/common/artsmodulescommon.idl167
-rw-r--r--arts/modules/common/effectrackslot_impl.cc116
-rw-r--r--arts/modules/common/env_container_impl.cc136
-rw-r--r--arts/modules/common/env_context_impl.cc72
-rw-r--r--arts/modules/common/env_effectrackitem_impl.cc400
-rw-r--r--arts/modules/common/env_instrumentitem_impl.cc113
-rw-r--r--arts/modules/common/env_item_impl.cc48
-rw-r--r--arts/modules/common/env_item_impl.h28
-rw-r--r--arts/modules/common/env_mixeritem_impl.cc368
-rw-r--r--arts/modules/common/mcopclass/Container.mcopclass3
-rw-r--r--arts/modules/common/mcopclass/EffectRackGuiFactory.mcopclass4
-rw-r--r--arts/modules/common/mcopclass/EffectRackItem.mcopclass3
-rw-r--r--arts/modules/common/mcopclass/InstrumentItem.mcopclass3
-rw-r--r--arts/modules/common/mcopclass/InstrumentItemGuiFactory.mcopclass4
-rw-r--r--arts/modules/common/mcopclass/MixerGuiFactory.mcopclass4
-rw-r--r--arts/modules/common/mcopclass/MixerItem.mcopclass3
-rw-r--r--arts/modules/effects/Makefile.am70
-rw-r--r--arts/modules/effects/artsmoduleseffects.idl147
-rw-r--r--arts/modules/effects/effect_wavecapture_impl.cc63
-rw-r--r--arts/modules/effects/fivebandmonocomplexeq_impl.cc208
-rw-r--r--arts/modules/effects/freeverb/Makefile.am5
-rw-r--r--arts/modules/effects/freeverb/allpass.cpp36
-rw-r--r--arts/modules/effects/freeverb/allpass.hpp48
-rw-r--r--arts/modules/effects/freeverb/comb.cpp48
-rw-r--r--arts/modules/effects/freeverb/comb.hpp55
-rw-r--r--arts/modules/effects/freeverb/denormals.h15
-rw-r--r--arts/modules/effects/freeverb/readme.txt67
-rw-r--r--arts/modules/effects/freeverb/revmodel.cpp257
-rw-r--r--arts/modules/effects/freeverb/revmodel.hpp87
-rw-r--r--arts/modules/effects/freeverb/tuning.h60
-rw-r--r--arts/modules/effects/freeverbguifactory_impl.cc107
-rw-r--r--arts/modules/effects/kstereovolumecontrolgui_impl.cpp132
-rw-r--r--arts/modules/effects/kstereovolumecontrolgui_impl.h97
-rw-r--r--arts/modules/effects/mcopclass/Effect_WAVECAPTURE.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/FiveBandMonoComplexEQ.mcopclass6
-rw-r--r--arts/modules/effects/mcopclass/FiveBandMonoComplexEQGuiFactory.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/FreeverbGuiFactory.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/MonoToStereo.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/StereoBalance.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/StereoBalanceGuiFactory.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/StereoCompressorGuiFactory.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/StereoFirEqualizerGuiFactory.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/StereoToMono.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/StereoVolumeControlGui.mcopclass5
-rw-r--r--arts/modules/effects/mcopclass/StereoVolumeControlGuiFactory.mcopclass6
-rw-r--r--arts/modules/effects/mcopclass/Synth_FREEVERB.mcopclass7
-rw-r--r--arts/modules/effects/mcopclass/Synth_STEREO_COMPRESSOR.mcopclass6
-rw-r--r--arts/modules/effects/mcopclass/Synth_STEREO_FIR_EQUALIZER.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/Synth_STEREO_PITCH_SHIFT.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/Synth_STEREO_PITCH_SHIFT_FFT.mcopclass4
-rw-r--r--arts/modules/effects/mcopclass/Synth_VOICE_REMOVAL.mcopclass7
-rw-r--r--arts/modules/effects/mcopclass/VoiceRemovalGuiFactory.mcopclass4
-rw-r--r--arts/modules/effects/monostereoconversion_impl.cc160
-rw-r--r--arts/modules/effects/stereocompressorguifactory_impl.cc114
-rw-r--r--arts/modules/effects/stereovolumecontrolguifactory_impl.cpp45
-rw-r--r--arts/modules/effects/synth_freeverb_impl.cc84
-rw-r--r--arts/modules/effects/synth_stereo_compressor_impl.cc135
-rw-r--r--arts/modules/effects/synth_stereo_fir_equalizer_impl.cc221
-rw-r--r--arts/modules/effects/synth_stereo_pitch_shift_fft_impl.cc63
-rw-r--r--arts/modules/effects/synth_stereo_pitch_shift_impl.cc51
-rw-r--r--arts/modules/effects/synth_voice_removal_impl.cc108
-rw-r--r--arts/modules/effects/voiceremovalguifactory_impl.cc76
-rw-r--r--arts/modules/mixers/Makefile.am60
-rw-r--r--arts/modules/mixers/artsmodulesmixers.idl81
-rw-r--r--arts/modules/mixers/littlestereomixerchannel_impl.cc134
-rw-r--r--arts/modules/mixers/mcopclass/LittleStereoMixerChannel.mcopclass4
-rw-r--r--arts/modules/mixers/mcopclass/LittleStereoMixerChannelGuiFactory.mcopclass4
-rw-r--r--arts/modules/mixers/mcopclass/MonoSimpleMixerChannel.mcopclass3
-rw-r--r--arts/modules/mixers/mcopclass/MonoSimpleMixerChannelGuiFactory.mcopclass4
-rw-r--r--arts/modules/mixers/mcopclass/SimpleMixerChannel.mcopclass3
-rw-r--r--arts/modules/mixers/mcopclass/SimpleMixerChannelGuiFactory.mcopclass4
-rw-r--r--arts/modules/mixers/monosimplemixerchannel_impl.cc106
-rw-r--r--arts/modules/mixers/monosimplemixerchannelguifactory_impl.cc96
-rw-r--r--arts/modules/mixers/simplemixerchannel_impl.cc132
-rw-r--r--arts/modules/mixers/simplemixerchannelguifactory_impl.cc86
-rw-r--r--arts/modules/synth/Makefile.am64
-rw-r--r--arts/modules/synth/artsmodulessynth.idl301
-rw-r--r--arts/modules/synth/c_filter_stuff.c984
-rw-r--r--arts/modules/synth/c_filter_stuff.h246
-rw-r--r--arts/modules/synth/mcopclass/Synth_ATAN_SATURATE.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_AUTOPANNER.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_BRICKWALL_LIMITER.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_CAPTURE_WAV.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_CDELAY.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_COMPRESSOR.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_DATA.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_DEBUG.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_DELAY.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_DIV.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_ENVELOPE_ADSR.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_FM_SOURCE.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_FX_CFLANGER.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_MIDI_DEBUG.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_MIDI_TEST.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_MOOG_VCF.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_NIL.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_NOISE.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_OSC.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_PITCH_SHIFT.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_PITCH_SHIFT_FFT.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_PLAY_PAT.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_PSCALE.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_RC.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_SEQUENCE.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_SEQUENCE_FREQ.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_SHELVE_CUTOFF.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_STD_EQUALIZER.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_TREMOLO.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_WAVE_PULSE.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_WAVE_SOFTSAW.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_WAVE_SQUARE.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_WAVE_TRI.mcopclass4
-rw-r--r--arts/modules/synth/mcopclass/Synth_XFADE.mcopclass4
-rw-r--r--arts/modules/synth/objectcache_impl.cc73
-rw-r--r--arts/modules/synth/synth_atan_saturate_impl.cc54
-rw-r--r--arts/modules/synth/synth_autopanner_impl.cc50
-rw-r--r--arts/modules/synth/synth_brickwall_limiter_impl.cc51
-rw-r--r--arts/modules/synth/synth_capture_wav_impl.cc169
-rw-r--r--arts/modules/synth/synth_cdelay_impl.cc125
-rw-r--r--arts/modules/synth/synth_compressor_impl.cc139
-rw-r--r--arts/modules/synth/synth_data_impl.cc50
-rw-r--r--arts/modules/synth/synth_debug_impl.cc60
-rw-r--r--arts/modules/synth/synth_delay_impl.cc138
-rw-r--r--arts/modules/synth/synth_div_impl.cc45
-rw-r--r--arts/modules/synth/synth_envelope_adsr_impl.cc121
-rw-r--r--arts/modules/synth/synth_fm_source_impl.cc61
-rw-r--r--arts/modules/synth/synth_fx_cflanger_impl.cc96
-rw-r--r--arts/modules/synth/synth_midi_debug_impl.cc88
-rw-r--r--arts/modules/synth/synth_midi_test_impl.cc692
-rw-r--r--arts/modules/synth/synth_moog_vcf_impl.cc91
-rw-r--r--arts/modules/synth/synth_nil_impl.cc36
-rw-r--r--arts/modules/synth/synth_noise_impl.cc63
-rw-r--r--arts/modules/synth/synth_osc_impl.cc253
-rw-r--r--arts/modules/synth/synth_pitch_shift_fft_impl.cc431
-rw-r--r--arts/modules/synth/synth_pitch_shift_impl.cc196
-rw-r--r--arts/modules/synth/synth_play_pat_impl.cc529
-rw-r--r--arts/modules/synth/synth_pscale_impl.cc53
-rw-r--r--arts/modules/synth/synth_rc_impl.cc110
-rw-r--r--arts/modules/synth/synth_sequence_freq_impl.cc131
-rw-r--r--arts/modules/synth/synth_sequence_impl.cc132
-rw-r--r--arts/modules/synth/synth_shelve_cutoff_impl.cc71
-rw-r--r--arts/modules/synth/synth_std_equalizer_impl.cc207
-rw-r--r--arts/modules/synth/synth_tremolo_impl.cc51
-rw-r--r--arts/modules/synth/synth_wave_pulse_impl.cc52
-rw-r--r--arts/modules/synth/synth_wave_softsaw_impl.cc50
-rw-r--r--arts/modules/synth/synth_wave_square_impl.cc39
-rw-r--r--arts/modules/synth/synth_wave_tri_impl.cc39
-rw-r--r--arts/modules/synth/synth_xfade_impl.cc45
-rw-r--r--arts/runtime/ArtsBuilderLoader.mcopclass4
-rw-r--r--arts/runtime/LocalFactory.mcopclass3
-rw-r--r--arts/runtime/Makefile.am38
-rw-r--r--arts/runtime/StructureBuilder.mcopclass3
-rw-r--r--arts/runtime/StructureDesc.mcopclass3
-rw-r--r--arts/runtime/artsbuilder.idl228
-rw-r--r--arts/runtime/artsbuilderloader_impl.cc285
-rw-r--r--arts/runtime/compatibility.cc56
-rw-r--r--arts/runtime/compatibility.h36
-rw-r--r--arts/runtime/localfactory_impl.cc15
-rw-r--r--arts/runtime/moduleinfo.cc106
-rw-r--r--arts/runtime/moduleinfo.h33
-rw-r--r--arts/runtime/sequenceutils.cc188
-rw-r--r--arts/runtime/sequenceutils.h41
-rw-r--r--arts/runtime/structurebuilder_impl.cc347
-rw-r--r--arts/runtime/structures_impl.cc1421
-rw-r--r--arts/tools/Makefile.am82
-rw-r--r--arts/tools/artsactions.cpp191
-rw-r--r--arts/tools/artsactions.h117
-rw-r--r--arts/tools/artscontrol.desktop136
-rw-r--r--arts/tools/artscontrol.rc17
-rw-r--r--arts/tools/artscontrolapplet.cpp163
-rw-r--r--arts/tools/artscontrolapplet.desktop109
-rw-r--r--arts/tools/artscontrolapplet.h132
-rw-r--r--arts/tools/artscontrolapplet_private.h122
-rw-r--r--arts/tools/artsmidimanagerview.rc9
-rw-r--r--arts/tools/audiomanager.cpp198
-rw-r--r--arts/tools/audiomanager.h79
-rw-r--r--arts/tools/choosebusdlg.cpp184
-rw-r--r--arts/tools/choosebusdlg.h49
-rw-r--r--arts/tools/environmentview.cpp171
-rw-r--r--arts/tools/environmentview.h57
-rw-r--r--arts/tools/fftscopeview.cpp163
-rw-r--r--arts/tools/fftscopeview.h81
-rw-r--r--arts/tools/levelmeters.cpp239
-rw-r--r--arts/tools/levelmeters.h168
-rw-r--r--arts/tools/main.cpp211
-rw-r--r--arts/tools/main.h110
-rw-r--r--arts/tools/mediatypesview.cpp76
-rw-r--r--arts/tools/mediatypesview.h36
-rw-r--r--arts/tools/midiinstdlg.cpp179
-rw-r--r--arts/tools/midiinstdlg.h38
-rw-r--r--arts/tools/midimanagerdlg.ui151
-rw-r--r--arts/tools/midimanagerview.cpp260
-rw-r--r--arts/tools/midimanagerview.h61
-rw-r--r--arts/tools/midimanagerwidget.ui135
-rw-r--r--arts/tools/midiportdlg.cpp111
-rw-r--r--arts/tools/midiportdlg.h42
-rw-r--r--arts/tools/pics/Makefile.am2
-rw-r--r--arts/tools/pics/cr128-action-artsaudiomanager.pngbin0 -> 8472 bytes
-rw-r--r--arts/tools/pics/cr128-action-artsenvironment.pngbin0 -> 12033 bytes
-rw-r--r--arts/tools/pics/cr128-action-artsfftscope.pngbin0 -> 3077 bytes
-rw-r--r--arts/tools/pics/cr128-action-artsmediatypes.pngbin0 -> 6904 bytes
-rw-r--r--arts/tools/pics/cr128-action-artsmidimanager.pngbin0 -> 16951 bytes
-rw-r--r--arts/tools/pics/cr16-action-artsaudiomanager.pngbin0 -> 815 bytes
-rw-r--r--arts/tools/pics/cr16-action-artsenvironment.pngbin0 -> 1008 bytes
-rw-r--r--arts/tools/pics/cr16-action-artsfftscope.pngbin0 -> 790 bytes
-rw-r--r--arts/tools/pics/cr16-action-artsmediatypes.pngbin0 -> 795 bytes
-rw-r--r--arts/tools/pics/cr16-action-artsmidimanager.pngbin0 -> 854 bytes
-rw-r--r--arts/tools/pics/cr22-action-artsaudiomanager.pngbin0 -> 1145 bytes
-rw-r--r--arts/tools/pics/cr22-action-artsenvironment.pngbin0 -> 1465 bytes
-rw-r--r--arts/tools/pics/cr22-action-artsfftscope.pngbin0 -> 1193 bytes
-rw-r--r--arts/tools/pics/cr22-action-artsmediatypes.pngbin0 -> 1082 bytes
-rw-r--r--arts/tools/pics/cr22-action-artsmidimanager.pngbin0 -> 1061 bytes
-rw-r--r--arts/tools/pics/cr32-action-artsaudiomanager.pngbin0 -> 1742 bytes
-rw-r--r--arts/tools/pics/cr32-action-artsenvironment.pngbin0 -> 2415 bytes
-rw-r--r--arts/tools/pics/cr32-action-artsfftscope.pngbin0 -> 1494 bytes
-rw-r--r--arts/tools/pics/cr32-action-artsmediatypes.pngbin0 -> 1597 bytes
-rw-r--r--arts/tools/pics/cr32-action-artsmidimanager.pngbin0 -> 2688 bytes
-rw-r--r--arts/tools/pics/cr48-action-artsaudiomanager.pngbin0 -> 2918 bytes
-rw-r--r--arts/tools/pics/cr48-action-artsenvironment.pngbin0 -> 4131 bytes
-rw-r--r--arts/tools/pics/cr48-action-artsfftscope.pngbin0 -> 1578 bytes
-rw-r--r--arts/tools/pics/cr48-action-artsmediatypes.pngbin0 -> 2396 bytes
-rw-r--r--arts/tools/pics/cr48-action-artsmidimanager.pngbin0 -> 4681 bytes
-rw-r--r--arts/tools/pics/cr64-action-artsaudiomanager.pngbin0 -> 4165 bytes
-rw-r--r--arts/tools/pics/cr64-action-artsenvironment.pngbin0 -> 5671 bytes
-rw-r--r--arts/tools/pics/cr64-action-artsfftscope.pngbin0 -> 2003 bytes
-rw-r--r--arts/tools/pics/cr64-action-artsmediatypes.pngbin0 -> 3245 bytes
-rw-r--r--arts/tools/pics/cr64-action-artsmidimanager.pngbin0 -> 6910 bytes
-rw-r--r--arts/tools/pics/crsc-action-artsaudiomanager.svgzbin0 -> 2150 bytes
-rw-r--r--arts/tools/pics/crsc-action-artsenvironment.svgzbin0 -> 2019 bytes
-rw-r--r--arts/tools/pics/crsc-action-artsfftscope.svgzbin0 -> 1203 bytes
-rw-r--r--arts/tools/pics/crsc-action-artsmediatypes.svgzbin0 -> 3323 bytes
-rw-r--r--arts/tools/pics/crsc-action-artsmidimanager.svgzbin0 -> 1746 bytes
-rw-r--r--arts/tools/pics/hi128-app-artscontrol.pngbin0 -> 7551 bytes
-rw-r--r--arts/tools/pics/hi16-app-artscontrol.pngbin0 -> 845 bytes
-rw-r--r--arts/tools/pics/hi22-app-artscontrol.pngbin0 -> 1172 bytes
-rw-r--r--arts/tools/pics/hi32-app-artscontrol.pngbin0 -> 1745 bytes
-rw-r--r--arts/tools/pics/hi48-app-artscontrol.pngbin0 -> 2642 bytes
-rw-r--r--arts/tools/pics/hi64-app-artscontrol.pngbin0 -> 3540 bytes
-rw-r--r--arts/tools/pics/hisc-app-artscontrol.svgzbin0 -> 2410 bytes
-rw-r--r--arts/tools/statusview.cpp95
-rw-r--r--arts/tools/statusview.h52
-rw-r--r--arts/tools/templateview.cpp39
-rw-r--r--arts/tools/templateview.h39
513 files changed, 65598 insertions, 0 deletions
diff --git a/arts/Makefile.am b/arts/Makefile.am
new file mode 100644
index 00000000..f98d9c01
--- /dev/null
+++ b/arts/Makefile.am
@@ -0,0 +1,9 @@
+if arts_within_KDE
+ARTS_BUILD_KDE=builder tools
+endif
+
+SUBDIRS = runtime midi gui modules examples $(ARTS_BUILD_KDE)
+DIST_SUBDIRS = runtime midi gui modules examples builder tools
+
+messages:
+ $(XGETTEXT) modules/*/*.cpp modules/*/*.cc gui/*/*.cpp gui/*/*.cc -o $(podir)/artsmodules.pot
diff --git a/arts/builder/FullDuplexTest.arts b/arts/builder/FullDuplexTest.arts
new file mode 100644
index 00000000..bcd6f753
--- /dev/null
+++ b/arts/builder/FullDuplexTest.arts
@@ -0,0 +1,139 @@
+name=FullDuplexTest
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=0
+ x=3
+ y=0
+ port=busname
+ {
+ id=1
+ string_data=in_soundcard
+ }
+ port=left
+ {
+ id=2
+ connect_to=9
+ }
+ port=right
+ {
+ id=3
+ connect_to=13
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=4
+ x=3
+ y=8
+ port=busname
+ {
+ id=5
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=6
+ connect_to=11
+ }
+ port=right
+ {
+ id=7
+ connect_to=15
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=8
+ x=3
+ y=5
+ port=invalue1
+ {
+ id=9
+ connect_to=2
+ }
+ port=invalue2
+ {
+ id=10
+ connect_to=25
+ }
+ port=outvalue
+ {
+ id=11
+ connect_to=6
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=12
+ x=6
+ y=5
+ port=invalue1
+ {
+ id=13
+ connect_to=3
+ }
+ port=invalue2
+ {
+ id=14
+ connect_to=25
+ }
+ port=outvalue
+ {
+ id=15
+ connect_to=7
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=16
+ x=0
+ y=0
+ port=frequency
+ {
+ id=17
+ audio_data=100.00000
+ }
+ port=pos
+ {
+ id=18
+ connect_to=20
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=19
+ x=1
+ y=1
+ port=pos
+ {
+ id=20
+ connect_to=18
+ }
+ port=outvalue
+ {
+ id=21
+ connect_to=23
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=22
+ x=2
+ y=2
+ port=invalue1
+ {
+ id=23
+ connect_to=21
+ }
+ port=invalue2
+ {
+ id=24
+ audio_data=12.00000
+ }
+ port=outvalue
+ {
+ id=25
+ connect_to=10
+ connect_to=14
+ }
+}
diff --git a/arts/builder/Makefile.am b/arts/builder/Makefile.am
new file mode 100644
index 00000000..3f5ce2b3
--- /dev/null
+++ b/arts/builder/Makefile.am
@@ -0,0 +1,39 @@
+SUBDIRS = pics
+# set the include path for X, qt, KDE, mico and the synthesizer class defs
+INCLUDES= -I$(top_srcdir)/arts/runtime -I$(top_builddir)/arts/runtime -I$(kde_includes)/arts $(all_includes)
+
+xdg_apps_DATA = artsbuilder.desktop
+
+kdemime_DATA = x-artsbuilder.desktop
+kdemimedir = $(kde_mimedir)/application
+
+bin_PROGRAMS = artsbuilder
+
+artsbuilder_SOURCES = autorouter.cpp main.cpp propertypanelbase.ui \
+ module.cpp propertypanel.cpp structure.cpp \
+ retrievedlg.cpp createtool.cpp structureport.cpp \
+ drawutils.cpp scomponent.cpp portposdlg.cpp \
+ menumaker.cpp session.cpp dirmanager.cpp mwidget.cpp \
+ execdlg.cpp qttableview.cpp interfacedlg.cpp
+artsbuilder_COMPILE_FIRST = ../runtime/artsbuilder.h
+
+noinst_HEADERS = qttableview.h
+
+METASOURCES = AUTO
+
+artsbuilder_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+# the libraries to link against. Be aware of the order. First the libraries,
+# that depend on the following ones.
+artsbuilder_LDADD = $(LIB_KFILE) -lqtmcop $(LIB_X11) $(LIBPTHREAD) $(top_builddir)/arts/runtime/libartsbuilder.la -lsoundserver_idl -lartskde
+
+rcdir = $(kde_datadir)/artsbuilder
+rc_DATA = artsbuilderui.rc
+
+# make messages.po. Move this one to ../po/ and "make merge" in po
+# the -x is for skipping messages already translated in kdelibs
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/artsbuilder.pot
+
+propertypanel.h: propertypanelbase.h
+
diff --git a/arts/builder/TODO b/arts/builder/TODO
new file mode 100644
index 00000000..139f22b2
--- /dev/null
+++ b/arts/builder/TODO
@@ -0,0 +1,69 @@
+Bugs:
+====
+- docked properties can be removed, but not fetched back
+
+Wishlist for the artsbuilder app:
+================================
+- implement File/New and provide templates
+- implement cut/copy/paste
+- implement undo
+- implement some preferences (e.g. zoom scale)
+
+- make application more KDE-like:
+ - icons in menus
+ - keyboard accelerators
+ - application icon(s)
+ - status bar
+ - session management
+ - tooltips and help
+ - kpart?
+
+- avoid crashing when loading a bad .arts file
+ (i.e. file open: wrong structure parameters like x/y pos)
+
+- ability to print a module view
+
+- don't allow execution of a structure with ports (like an instrument) directly
+
+- editing of structures while they are running (*)
+- wysiwyg editing of visual structures (like qt designer/delphi), requires (*)
+
+- provide a property dialog like
+ +----------+--------+
+ | property | value |
+ +----------+--------+
+ | caption | hello |
+ | width | 20 |
+ | height | 100 |
+ | x | 30 |
+ | y | 30 |
+ +----------+--------+
+ this should be very useful in editing objects with lots of properties
+ (widgets)
+
+- make _changed signals visible so you can connect the value_changed of a
+ poti to the frequency of a filter
+
+- make it possible to edit parent property of widgets (i.e. to insert one
+ widget into another)
+
+- add structure property dialog with structure meta information, at least
+ * (class) name
+ * (real world) name with i18n (?)
+ * implemented interfaces
+ * ports (maybe Details >>, tabbed notebook) - like already implemented
+ * author
+ * (category for menues)
+ * copyright
+ * license
+ * whether to publish or not (?)
+ * template (?)
+
+Additions "outside" the app code:
+================================
+- create standalone command line tool to load modules that does not
+ depend on KDE
+
+- write a tutorial in the arts manual
+
+- create more bitmaps/icons for all modules
diff --git a/arts/builder/artsbuilder.desktop b/arts/builder/artsbuilder.desktop
new file mode 100644
index 00000000..9d99c6d7
--- /dev/null
+++ b/arts/builder/artsbuilder.desktop
@@ -0,0 +1,122 @@
+# KDE Config File
+[Desktop Entry]
+Name=aRts Builder
+Name[af]=Arts Builder
+Name[ar]=باني Arts
+Name[bn]=আর্ট্‌স্ বিল্ডার
+Name[br]=arts Builder
+Name[ca]=Constructor aRts
+Name[cs]=Konstruktér aRts
+Name[cy]=Adeiladwr aRts
+Name[da]=aRts-bygger
+Name[de]=aRts-Builder
+Name[eo]=aRts-Sonkreilo
+Name[et]=aRtsi ehitaja
+Name[fa]=سازندۀ aRts
+Name[fi]=aRts-rakentaja
+Name[fr]=aRtsBuilder
+Name[gl]=Construtor aRts
+Name[hi]=एआरटीएस बिल्डर
+Name[hu]=aRts-modellező
+Name[is]=aRts-smiður
+Name[it]=Costruttore per aRts
+Name[ja]=aRts ビルダー
+Name[kk]=aRts құрастырғышы
+Name[km]=កម្មវិធី​បង្កើត aRts
+Name[ko]=aRts 빌더
+Name[lt]=aRts komponuoklis
+Name[lv]=aRts Būvētājs
+Name[mk]=Градител на aRts
+Name[nb]=aRts-bygger
+Name[nds]=aRts-Builder
+Name[ne]=aRts निर्माता
+Name[nn]=aRts-byggjar
+Name[pa]=aRts ਨਿਰਮਾਤਾ
+Name[pl]=Arts Builder
+Name[pt]=Construtor do aRts
+Name[pt_BR]=Construtor Arts
+Name[ru]=artsbuilder
+Name[se]=aRts-huksejeaddji
+Name[sl]=Graditelj aRts
+Name[sr]=Градитељ Rts-а
+Name[sr@Latn]=Graditelj Rts-a
+Name[sv]=Arts-byggare
+Name[ta]=aRts உருவாக்கி
+Name[tg]=Созандаи aRts
+Name[tr]=aRts
+Name[ven]=Mufhati wa aRts
+Name[xh]=Umakhi we aRts
+Name[zh_CN]=aRts 构建程序
+Name[zu]=Umakhi We aRts
+GenericName=Audio Filter Designer
+GenericName[af]=Audio Filter Ontwerper
+GenericName[bg]=Аудио дизайнер
+GenericName[bn]=অডিও ফিল্টার ডিসাইনার
+GenericName[br]=Ergrafer sil klevet
+GenericName[bs]=Dizajner audio filtera
+GenericName[ca]=Dissenyador de filtres àudio
+GenericName[cs]=Návrhář zvukových filtrů
+GenericName[cy]=Dylunydd Hidl Sain
+GenericName[da]=Audiofilter-designer
+GenericName[de]=Audiofilter-Designer
+GenericName[el]=Σχεδιαστής φίλτρων ήχου
+GenericName[eo]=Aŭdfiltrilo-desegnilo
+GenericName[es]=Diseñador de filtros de audio
+GenericName[et]=Audiofiltrite disainer
+GenericName[eu]=Audio iragazki diseinatzailea
+GenericName[fa]=طراح پالایۀ صوتی
+GenericName[fi]=Äänisuodattimien suunnitteluohjelma
+GenericName[fr]=Concepteur de filtre audio
+GenericName[ga]=Dearthóir Scagaire Fuaime
+GenericName[gl]=Deseñador de Filtros de Son
+GenericName[he]=מעצב מסנני שמע
+GenericName[hi]=ध्वनि फ़िल्टर डिजाइनर
+GenericName[hr]=Dizajner audio filtara
+GenericName[hu]=Hangszűrő-tervező
+GenericName[is]=Hljóðsíuhönnuður
+GenericName[it]=Disegnatore di filtro audio
+GenericName[ja]=オーディオフィルタデザイナー
+GenericName[kk]=Аудио сүзгі құрастырғышы
+GenericName[km]=កម្មវិធី​រចនាតម្រង​អូ​ឌីយូ​
+GenericName[ko]=오디오 필터 디자이너
+GenericName[lt]=Audio filtrų kūrimo priemonė
+GenericName[mk]=Изработувач на филтри за звук
+GenericName[ms]=Pereka Penapis Audio
+GenericName[nb]=Lydfilterdesigner
+GenericName[nds]=Klangfilter-Maker
+GenericName[ne]=अडियो फिल्टर डिजाइनर
+GenericName[nl]=Audiofilterontwerper
+GenericName[nn]=Utforming av lydfilter
+GenericName[pa]=ਆਡੀਓ ਫਿਲਟਰ ਡਿਜ਼ਾਈਨਰ
+GenericName[pl]=Projektant filtru audio
+GenericName[pt]=Editor de Filtros de Áudio
+GenericName[pt_BR]=Criador de Filtro de Áudio
+GenericName[ro]=Proiectare filtre audio
+GenericName[ru]=Дизайнер звуковых фильтров
+GenericName[se]=Jietnasilli hápmejeaddji
+GenericName[sk]=Návrh audio filtrov
+GenericName[sl]=Snovalnik avdio filtrov
+GenericName[sr]=Дизајнер аудио филтера
+GenericName[sr@Latn]=Dizajner audio filtera
+GenericName[sv]=Ljudfilterdesigner
+GenericName[ta]=கேட்பொலி வடிகட்டி படைப்பாளர்
+GenericName[tg]=Тарроҳи Полоягари Садо
+GenericName[th]=เครื่องมือออกแบบฟิลเตอร์ของเสียง
+GenericName[tr]=Ses Filtresi Tasarlayıcı
+GenericName[uk]=Дизайн аудіофільтрів
+GenericName[ven]=Muvhati wa filithara ino pfala
+GenericName[xh]=Umyili Wecebo lokucoca ulwelo Wesandi
+GenericName[zh_CN]=音频滤波器设计程序
+GenericName[zh_HK]=音訊過濾器設計師
+GenericName[zh_TW]=音效過濾器設計師
+GenericName[zu]=Umdwebi Wehluzo Lokuzwakalayo
+Exec=artsbuilder -caption "%c"
+Icon=artsbuilder
+Path=
+Type=Application
+Terminal=false
+MimeType=application/x-artsbuilder;
+DocPath=artsbuilder/index.html
+X-DCOP-ServiceType=Multi
+OnlyShowIn=KDE;
+Categories=Qt;KDE;AudioVideo;X-KDE-More;
diff --git a/arts/builder/artsbuilderui.rc b/arts/builder/artsbuilderui.rc
new file mode 100644
index 00000000..807d511f
--- /dev/null
+++ b/arts/builder/artsbuilderui.rc
@@ -0,0 +1,47 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="Artsbuilder" version="3">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_open_example" append="new_merge"/>
+ <Action name="file_execute_structure"/>
+ <Action name="file_rename_structure"/>
+ <!-- currently unused
+ <Action name="file_open_session" append="new_merge"/>
+ <Action name="file_publish_structure"/>
+ <Action name="file_retrieve_from_server"/>
+ -->
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="edit_delete"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="view_properties"/>
+ <Separator/>
+ <Action name="view_200"/>
+ <Action name="view_150"/>
+ <Action name="view_100"/>
+ <Action name="view_50"/>
+ </Menu>
+ <Action name="modulesmenu"/>
+ <!--
+ <Menu name="modules"><text>&amp;Modules</text>
+ <Action name="modulesmenu"/>
+ <Separator/>
+ </Menu>
+ -->
+ <Menu name="ports"><text>&amp;Ports</text>
+ <Action name="ports_create_in_audio_signal"/>
+ <Action name="ports_create_out_audio_signal"/>
+ <Action name="ports_create_in_string_property"/>
+ <Action name="ports_create_in_audio_property"/>
+ <Separator/>
+ <Action name="ports_implement_interface"/>
+ <Separator/>
+ <Action name="ports_change_positions"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar" ><text>Main Toolbar</text>
+ <Separator />
+ <Action name="file_execute_structure"/>
+</ToolBar>
+</kpartgui>
diff --git a/arts/builder/autorouter.cpp b/arts/builder/autorouter.cpp
new file mode 100644
index 00000000..bc69a7ee
--- /dev/null
+++ b/arts/builder/autorouter.cpp
@@ -0,0 +1,609 @@
+ /*
+
+ Copyright (C) 1998 Stefan Westerfeld <stefan@space.twc.de>,
+ 2002 Hans Meine <hans_meine@gmx.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ */
+
+#include "autorouter.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <arts/debug.h>
+
+#include <kdebug.h>
+
+#ifndef HAVE_LIBPTHREAD
+#define pthread_create(a, b, c, d) ;
+#define pthread_join(a, b) ;
+#define pthread_mutex_lock(a) ;
+#define pthread_mutex_unlock(a) ;
+#define pthread_mutex_init(a, b) ;
+#define pthread_attr_init(a) ;
+#endif
+
+using namespace std;
+
+const int COST_INIT = 200000;
+const int PENALTY_OTHERCONNECTION = 100;
+const int PENALTY_CORNER = 100;
+const int IDLE_SLEEP_MILLISECONDS = 40;
+
+void *startroute(void *where)
+{
+ ((AutoRouter *)where)->thread_command_loop();
+ // just to prevent the compiler warning
+ return 0;
+}
+
+bool ARCommand::isDestructive()
+{
+ return false;
+}
+
+AutoRouter::AutoRouter(int width, int height)
+ : width(width), height(height)
+{
+#ifdef HAVE_LIBPTHREAD
+ pthread_attr_t attrs;
+
+ pthread_attr_init(&attrs);
+ pthread_mutex_init(&mutex_sync, 0);
+ pthread_mutex_init(&mutex_queue, 0);
+#endif
+
+ // allocate memory for fields..
+ field = new Field*[width];
+ completeField = new Field*[width];
+
+ for(int i = 0; i < width; i++)
+ {
+ field[i] = new Field[height];
+ completeField[i] = new Field[height];
+ }
+
+ // ..and clear the freshly allocated memory
+ thread_clear();
+ thread_sync();
+
+ newOwner = 1;
+
+ // init those two arrays - they should be constant somehow..
+ directionMask[DIR_DOWN] = ~(left | right);
+ directionMask[DIR_UP] = ~(left | right);
+ directionMask[DIR_LEFT] = ~(up | down);
+ directionMask[DIR_RIGHT] = ~(up | down);
+
+ ownerIndex[DIR_DOWN] = OWNER_UD;
+ ownerIndex[DIR_UP] = OWNER_UD;
+ ownerIndex[DIR_LEFT] = OWNER_LR;
+ ownerIndex[DIR_RIGHT] = OWNER_LR;
+
+ initPseudoRandom();
+
+ thread_terminate_now = false; // not yet
+#ifdef HAVE_LIBPTHREAD
+ // setup thread and run thread_command_loop() in it
+ pthread_create(&route_thread, &attrs, startroute, this);
+#endif
+
+ arts_debug("AR UP...");
+}
+
+void AutoRouter::initPseudoRandom()
+{
+ // init pseudoRandomDir array with random directions
+
+ int remainingDirs[4];
+ for(int i = 0; i < PRSIZE; i++)
+ {
+ if((i & 3) == 0)
+ {
+ int j = 0;
+ for(int dir = DIR_UP; dir <= DIR_RIGHT; dir++)
+ remainingDirs[j++] = dir;
+ }
+
+ int rnd;
+ do rnd = rand()&3;
+ while(remainingDirs[rnd] == DIR_NONE);
+
+ pseudoRandomDir[i] = remainingDirs[rnd];
+
+ remainingDirs[rnd] = DIR_NONE;
+ }
+ nextPR = 0;
+}
+
+AutoRouter::~AutoRouter()
+{
+ // tell the thread to shut down
+ pthread_mutex_lock(&mutex_queue);
+ thread_terminate_now = true;
+ pthread_mutex_unlock(&mutex_queue);
+
+ // terminate thread
+ void *rc;
+ pthread_join(route_thread, &rc);
+
+ // clean up
+ for(int i = 0; i < width; i++)
+ {
+ delete[] field[i];
+ delete[] completeField[i];
+ }
+ delete[] completeField;
+ delete[] field;
+
+ arts_debug("AR DOWN...");
+}
+
+void AutoRouter::enqueue(ARCommand *command)
+{
+#ifdef HAVE_LIBPTHREAD
+ // threaded execution, locking the queue
+ pthread_mutex_lock(&mutex_queue);
+
+ if(command->isDestructive())
+ {
+ // ok, then we can kill the whole list, since this will clear
+ // the whole results anyway
+
+ command_queue.setAutoDelete(true);
+ command_queue.clear();
+ command_queue.setAutoDelete(false);
+ }
+ command_queue.append(command);
+
+ pthread_mutex_unlock(&mutex_queue);
+#else
+ // immediate execution
+ command->execute(this);
+ delete command;
+#endif
+}
+
+void AutoRouter::thread_command_loop()
+{
+ while(1)
+ {
+ ARCommand *command = 0;
+
+ // pop one command from queue if possible..
+ pthread_mutex_lock(&mutex_queue);
+ if(!command_queue.isEmpty())
+ {
+ command = command_queue.first();
+ command_queue.remove(unsigned(0));
+ }
+ else
+ {
+ if (thread_terminate_now) {
+ pthread_mutex_unlock(&mutex_queue);
+ return;
+ }
+ }
+ pthread_mutex_unlock(&mutex_queue);
+
+ // ..and execute command if we got one
+ if(command)
+ {
+ command->execute(this);
+ delete command;
+ }
+ else // no more commands->wait for some milliseconds
+ usleep(1000 * IDLE_SLEEP_MILLISECONDS);
+ // TODO: use pthread_cond_wait here instead of half-busy-waiting?
+ }
+}
+
+// ------------------------- getXXX() handling -------------------------
+
+long AutoRouter::get(int x, int y)
+{
+ assert(x >= 0 && x < width);
+ assert(y >= 0 && y < height);
+
+ pthread_mutex_lock(&mutex_sync);
+ long result = completeField[x][y].data;
+ pthread_mutex_unlock(&mutex_sync);
+
+ return(result);
+}
+
+void AutoRouter::getowners(int x, int y, long& ud_owner, long& lr_owner)
+{
+ assert(x >= 0 && x < width);
+ assert(y >= 0 && y < height);
+
+ pthread_mutex_lock(&mutex_sync);
+ ud_owner = completeField[x][y].owner[OWNER_UD];
+ lr_owner = completeField[x][y].owner[OWNER_LR];
+ pthread_mutex_unlock(&mutex_sync);
+}
+
+// ------------------------- sync() handling -------------------------
+
+void AutoRouter::sync()
+{
+ enqueue(new ARSyncCommand());
+}
+
+void ARSyncCommand::execute(AutoRouter *router)
+{
+ router->thread_sync();
+}
+
+void AutoRouter::thread_sync()
+{
+ int i;
+ pthread_mutex_lock(&mutex_sync);
+
+ for(i = 0; i < width; i++)
+ memcpy(completeField[i], field[i], sizeof(Field)*height);
+ _needRedraw = true;
+
+ pthread_mutex_unlock(&mutex_sync);
+}
+
+bool AutoRouter::needRedraw()
+{
+ bool result;
+
+ pthread_mutex_lock(&mutex_sync);
+ result = _needRedraw;
+ _needRedraw = false;
+#ifdef AR_DEBUG
+ if(result) arts_debug("NEED REDRAW NOW!");
+#endif
+ pthread_mutex_unlock(&mutex_sync);
+
+ return result;
+}
+
+// ------------------------- clear() handling -------------------------
+
+void AutoRouter::clear()
+{
+ enqueue(new ARClearCommand());
+}
+
+bool ARClearCommand::isDestructive()
+{
+ return true;
+}
+
+void ARClearCommand::execute(AutoRouter *router)
+{
+ router->thread_clear();
+}
+
+void AutoRouter::thread_clear()
+{
+ arts_debug("clear()ing now...");
+ int x, y;
+
+ for(x = 0; x < width; x++)
+ for(y = 0; y < height; y++)
+ {
+ field[x][y].data = none;
+ field[x][y].penalty = 0;
+ field[x][y].owner[0] = -1;
+ field[x][y].owner[1] = -1;
+ }
+}
+
+// ------------------------- set() command handling -------------------------
+
+void AutoRouter::set(int x1, int y1, int x2, int y2, long lt)
+{
+ enqueue(new ARSetCommand(x1, y1, x2, y2, lt));
+}
+
+ARSetCommand::ARSetCommand(int x1, int y1, int x2, int y2, long lt)
+ : _x1(x1), _y1(y1), _x2(x2), _y2(y2), _lt(lt)
+{
+}
+
+void ARSetCommand::execute(AutoRouter *router)
+{
+ router->thread_set(_x1, _y1, _x2, _y2, _lt);
+}
+
+void AutoRouter::thread_set(int x1, int y1, int x2, int y2, long lt)
+{
+ for(int x = x1; x <= x2; x++)
+ {
+ for(int y = y1; y <= y2; y++)
+ {
+ assert(x >= 0 && x < width);
+ assert(y >= 0 && y < height);
+
+ if(lt & solid)
+ {
+ if((y - 1) >= 0)
+ field[x][y - 1].penalty += 5;
+
+ if((y - 2) >= 0)
+ field[x][y - 2].penalty += 2;
+
+ if((y + 1) < height)
+ field[x][y + 1].penalty += 5;
+
+ if((y + 2) < height)
+ field[x][y + 2].penalty += 2;
+ }
+
+ field[x][y].data = lt;
+ field[x][y].owner[0] = 0;
+ field[x][y].owner[1] = 0; // don't pass
+ }
+ }
+}
+
+
+long AutoRouter::connect(int x1, int y1, int x2, int y2, long owner)
+{
+ if(owner == 0)
+ owner = newOwner++;
+
+ enqueue(new ARConnectCommand(x1, y1, x2, y2, owner));
+
+ return owner;
+}
+
+ARConnectCommand::ARConnectCommand(int x1, int y1, int x2, int y2, long owner)
+{
+ _x1 = x1; _y1 = y1; _x2 = x2; _y2 = y2; _owner = owner;
+}
+
+void ARConnectCommand::execute(AutoRouter *router)
+{
+ router->thread_connect(_x1, _y1, _x2, _y2, _owner);
+}
+
+void AutoRouter::thread_connect(int x1, int y1, int x2, int y2, long owner)
+{
+ currentOwner = owner;
+
+#ifdef AR_DEBUG
+ arts_debug("-field[x1][y1].owner[0..1] = %ld, %ld",field[x1][y1].owner[0],
+ field[x1][y1].owner[1]);
+ arts_debug("-field[x2][y2].owner[0..1] = %ld, %ld", field[x2][y2].owner[0],
+ field[x2][y2].owner[1]);
+#endif
+
+ // clear data(source) & data(dest) first and restore later, since
+ // they might be solid
+ long sourceFieldData = field[x1][y1].data; field[x1][y1].data = none;
+ long destFieldData = field[x2][y2].data; field[x2][y2].data = none;
+
+ for(int x = 0; x < width; x++)
+ for(int y = 0; y < height; y++)
+ field[x][y].minCost = COST_INIT;
+
+#ifdef AR_DEBUG
+ arts_debug("autorouter: trying to connect %d, %d with %d, %d (owner %ld)",
+ x1, y1, x2, y2, owner);
+#endif
+ nextPR = 0;
+
+ bestGoalPath.cost = COST_INIT;
+
+ int activelist = 0;
+ numQueuedPaths = 0;
+
+ PathInfo path;
+ path.x1 = x1;
+ path.x2 = x2;
+ path.y1 = y1;
+ path.y2 = y2;
+ path.cost = 0;
+ path.depth = 0;
+ queuePath(path);
+
+ while(numQueuedPaths)
+ {
+ while(!pathlist[activelist].size())
+ activelist++;
+ PathQueue& activePathList =
+ pathlist[activelist];
+
+ assert(activePathList.size());
+ examinePath(activePathList.first());
+ activePathList.pop_front();
+ numQueuedPaths--;
+ }
+
+ field[x1][y1].data = sourceFieldData;
+ field[x2][y2].data = destFieldData;
+
+ if(bestGoalPath.cost != COST_INIT)
+ {
+ //arts_debug("bestGoalPath.history for this connection is %s", bestGoalPath.history.data());
+ //arts_debug("minCost for that was %d", gms);
+
+ const char *walk = bestGoalPath.history.ascii();
+
+ int x = x1;
+ int y = y1;
+
+ while(*walk)
+ {
+ field[x][y].owner[ownerIndex[*walk]] = currentOwner;
+ switch(*walk)
+ {
+ case DIR_DOWN:
+ field[x][y++].data |= down;
+ field[x][y].data |= up;
+ break;
+ case DIR_UP:
+ field[x][y--].data |= up;
+ field[x][y].data |= down;
+ break;
+ case DIR_LEFT:
+ field[x--][y].data |= left;
+ field[x][y].data |= right;
+ break;
+ case DIR_RIGHT:
+ field[x++][y].data |= right;
+ field[x][y].data |= left;
+ break;
+ }
+ field[x][y].owner[ownerIndex[*walk]] = currentOwner;
+ walk++;
+ }
+ }
+ else
+ {
+#ifdef AR_DEBUG
+ arts_debug("!! sorry, this connection is impossible !!");
+#endif
+ }
+}
+
+void AutoRouter::queuePath(const PathInfo &path)
+{
+ PathInfo newPath = path;
+
+ int targetlist = newPath.cost/5;
+ if(targetlist > 1023)
+ targetlist = 1023;
+
+ pathlist[targetlist].append(newPath);
+ qHeapSort(pathlist[targetlist]);
+
+ numQueuedPaths++;
+}
+
+void AutoRouter::examinePath(const PathInfo &path)
+{
+ const char *walk = path.history.ascii();
+
+// check if we can go here:
+
+ if(path.x1 < 0 || path.x1 >= width)
+ return;
+ if(path.y1 < 0 || path.y1 >= width)
+ return;
+
+ int currentFieldCost = path.cost;
+
+ if(path.depth > 0)
+ {
+ // going over a field where already connections are is bad
+ if(field[path.x1][path.y1].data != 0)
+ currentFieldCost += PENALTY_OTHERCONNECTION;
+
+ if(directionMask[walk[path.depth - 1]] & field[path.x1][path.y1].data)
+ {
+ // someone already uses that field... we can continue
+ // only if the connection has the same sourceport
+
+ long fieldowner = field[path.x1][path.y1].owner[ownerIndex[walk[path.depth - 1]]];
+
+ if(fieldowner != -1) // used?
+ {
+ if(fieldowner != currentOwner)
+ return;
+
+ // oops, the connections are from the same owner -> no
+ // penalty needed!
+ currentFieldCost -= PENALTY_OTHERCONNECTION;
+ }
+ }
+ }
+
+ // add cityblock distance to costs
+ currentFieldCost += abs(path.x1 - path.x2) + abs(path.y1 - path.y2);
+
+ // add field penalty to costs
+ currentFieldCost += field[path.x1][path.y1].penalty;
+
+ // add corner penalty to costs if path had corner here
+ if(path.depth > 2)
+ if(walk[path.depth - 2] != walk[path.depth - 1])
+ currentFieldCost += PENALTY_CORNER;
+
+ if(currentFieldCost > bestGoalPath.cost)
+ return;
+
+ // better path found?
+ if(currentFieldCost < field[path.x1][path.y1].minCost)
+ {
+ field[path.x1][path.y1].minCost = currentFieldCost;
+
+ // check if we are where we wanted to be:
+ if(path.x1 == path.x2 && path.y1 == path.y2) {
+ // goal! success! :-)
+
+ if(path.cost < bestGoalPath.cost)
+ {
+ bestGoalPath = path; // best solution until now
+ bestGoalPath.cost = currentFieldCost;
+ }
+
+ return;
+ }
+
+ // not at the goal yet, search next place to go; take some
+ // pseudo random direction order (this method improves search
+ // speed)
+
+ PathInfo newPath = path;
+ newPath.depth++;
+ newPath.cost = currentFieldCost;
+
+ for(int i = 0; i < 4; i++)
+ {
+ if(nextPR >= PRSIZE)
+ nextPR = 0;
+
+ switch(pseudoRandomDir[nextPR++])
+ {
+ case DIR_LEFT:
+ newPath.x1--;
+ newPath.history = path.history + (char)DIR_LEFT;
+ queuePath(newPath);
+ newPath.x1++;
+ break;
+
+ case DIR_RIGHT:
+ newPath.x1++;
+ newPath.history = path.history + (char)DIR_RIGHT;
+ queuePath(newPath);
+ newPath.x1--;
+ break;
+
+ case DIR_UP:
+ newPath.y1--;
+ newPath.history = path.history + (char)DIR_UP;
+ queuePath(newPath);
+ newPath.y1++;
+ break;
+
+ case DIR_DOWN:
+ newPath.y1++;
+ newPath.history = path.history + (char)DIR_DOWN;
+ queuePath(newPath);
+ newPath.y1--;
+ break;
+ }
+ }
+ }
+}
diff --git a/arts/builder/autorouter.h b/arts/builder/autorouter.h
new file mode 100644
index 00000000..df3780a0
--- /dev/null
+++ b/arts/builder/autorouter.h
@@ -0,0 +1,184 @@
+/*
+
+ Copyright (C) 1998 Stefan Westerfeld <stefan@space.twc.de>,
+ 2002 Hans Meine <hans_meine@gmx.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ */
+
+#ifndef __AUTOROUTER_H_
+#define __AUTOROUTER_H_
+
+// If you get into trouble with threading (random crashes), you can configure
+// things with --disable-threading, which should fix everything by not using
+// threads
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_LIBPTHREAD
+#include <pthread.h>
+#endif
+
+#include <qptrlist.h>
+#include <qvaluelist.h>
+
+class PathInfo
+{
+public:
+ int x1, x2, y1, y2, cost, depth;
+ QString history;
+ int operator<(const PathInfo& x) const { return cost < x.cost; }
+ int operator==(const PathInfo& x) const { return cost == x.cost; }
+};
+
+typedef QValueList<PathInfo> PathQueue;
+
+class ARCommand;
+
+/**
+ * The AutoRouter uses threads, commands are passed as objects via
+ * AutoRouter::enqueue() to the routing thread.
+ */
+class AutoRouter
+{
+public:
+ enum { none=0,up=1,down=2,left=4,right=8,head=16,tail=32,solid=64 };
+ enum Direction { DIR_NONE=0, DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT };
+
+protected:
+ int width, height;
+
+ enum OwnerType { OWNER_UD=0, OWNER_LR=1 };
+ OwnerType ownerIndex[DIR_RIGHT + 1]; // index is of type Direction
+ long directionMask[DIR_RIGHT + 1]; // index is of type Direction
+
+ struct Field
+ {
+ long data;
+ long minCost;
+ long penalty;
+ long owner[2];
+ } **field, **completeField;
+
+ long newOwner; // next free owner ID
+ long currentOwner;
+
+ bool _needRedraw;
+
+ PathInfo bestGoalPath;
+ PathQueue pathlist[1024];
+ int numQueuedPaths;
+
+ // pseudo random table for fast "random" decisions
+ enum { PRSIZE = 16 };
+ long pseudoRandomDir[PRSIZE];
+ int nextPR;
+ void initPseudoRandom();
+
+/****** thread stuff *****/
+#ifdef HAVE_LIBPTHREAD
+ pthread_mutex_t mutex_sync;
+ pthread_mutex_t mutex_queue;
+
+ pthread_t route_thread;
+#endif
+ QPtrList<ARCommand> command_queue;
+
+ bool thread_terminate_now;
+/*************************/
+
+ void queuePath(const PathInfo &path);
+ void examinePath(const PathInfo &path);
+
+public:
+ AutoRouter(int width, int height);
+ ~AutoRouter();
+
+ // queries _needRedraw flag and deletes it
+ // (assuming that the client is smart and redraws when getting true ;)
+ bool needRedraw();
+
+ long get(int x, int y);
+ void getowners(int x, int y, long& ud_owner, long& lr_owner);
+
+ void enqueue(ARCommand *command);
+
+ // marks the entire field as unused
+ void clear();
+ // sets the
+ void set(int x1, int y1, int x2, int y2, long lt);
+ long connect(int x1, int y1, int x2, int y2, long owner);
+ //
+ void sync();
+
+ // the following functions are not for direct use; they're used
+ // for threading only
+ void thread_clear();
+ void thread_set(int x1, int y1, int x2, int y2, long lt);
+ void thread_connect(int x1, int y1, int x2, int y2, long owner);
+ void thread_sync();
+
+ void thread_command_loop();
+};
+
+/**
+ * The ARCommand classes are used to communicate with the routing
+ * thread, see AutoRouter::enqueue()
+ */
+class ARCommand
+{
+public:
+ virtual void execute(AutoRouter *autorouter) = 0;
+ // if a command is destructive (default: false), the command queue
+ // will be emptied before queuing this one, assuming it'll destroy
+ // results of all other commands anyway.
+ virtual bool isDestructive();
+};
+
+class ARClearCommand :public ARCommand
+{
+public:
+ void execute(AutoRouter *autorouter);
+ bool isDestructive();
+};
+
+class ARSyncCommand :public ARCommand
+{
+public:
+ void execute(AutoRouter *autorouter);
+};
+
+class ARConnectCommand :public ARCommand
+{
+ int _x1, _y1, _x2, _y2;
+ long _owner;
+public:
+ ARConnectCommand(int x1, int y1, int x2, int y2, long owner);
+ void execute(AutoRouter *autorouter);
+};
+
+class ARSetCommand :public ARCommand
+{
+private:
+ int _x1, _y1, _x2, _y2;
+ long _lt;
+public:
+ ARSetCommand(int x1, int y1, int x2, int y2, long lt);
+ void execute(AutoRouter *autorouter);
+};
+
+#endif
diff --git a/arts/builder/createtool.cpp b/arts/builder/createtool.cpp
new file mode 100644
index 00000000..a96edc6d
--- /dev/null
+++ b/arts/builder/createtool.cpp
@@ -0,0 +1,339 @@
+ /*
+
+ Copyright (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 "createtool.h"
+
+#include "mwidget.h"
+#include "structureport.h"
+
+//#include <arts/debug.h>
+#include <qpalette.h>
+#include <qpainter.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+MWidgetTool::MWidgetTool(ModuleWidget *mwidget)
+{
+ this->mwidget = mwidget;
+}
+
+MWidgetTool::~MWidgetTool()
+{
+}
+
+CreateTool::CreateTool(ModuleWidget *mwidget)
+ : MWidgetTool(mwidget)
+{
+ oldCursor = mwidget->cursor();
+ mwidget->setCursor(Qt::crossCursor);
+
+ oldMouseTracking = mwidget->hasMouseTracking();
+ mwidget->setMouseTracking(true);
+
+ width = -1;
+ height = -1;
+ componentRect = QRect(0, 0, 0, 0);
+}
+
+CreateTool::~CreateTool()
+{
+ mwidget->repaint(componentRect);
+ mwidget->setCursor(oldCursor);
+ mwidget->setMouseTracking(oldMouseTracking);
+}
+
+void CreateTool::mousePressEvent(QMouseEvent *e)
+{
+ int x = mwidget->findCol(e->x());
+ int y = mwidget->findRow(e->y());
+
+ if(x < 0 || y < 0) return;
+
+ if( e->button() == Qt::LeftButton )
+ performCreate(x, y);
+
+ // well, perhaps make this an option
+ mwidget->leaveTool(this);
+}
+
+void CreateTool::mouseMoveEvent(QMouseEvent *e)
+{
+ if(width == -1) estimateSize();
+
+ int x = mwidget->findCol(e->x());
+ int y = mwidget->findRow(e->y());
+
+ if(x < 0 || y < 0) return;
+
+ int cellx, celly, cellx2, celly2;
+
+ bool posok = mwidget->colXPos(x, &cellx) && mwidget->rowYPos(y, &celly)
+ && mwidget->colXPos(x + width, &cellx2) && mwidget->rowYPos(y + height, &celly2);
+ if(!posok) return;
+
+ mwidget->repaint(componentRect);
+ componentRect = QRect(cellx, celly, cellx2 - cellx, celly2 - celly);
+
+ QPainter *p = new QPainter;
+
+ p->begin(mwidget);
+ p->save();
+ p->drawRect(componentRect);
+ p->restore();
+ p->end();
+ delete p;
+}
+
+void CreateTool::mouseReleaseEvent(QMouseEvent *e)
+{
+}
+
+// module creation
+
+void CreateModuleTool::estimateSize()
+{
+// yes, this is a it ugly: we create here the new module for a microsecond,
+// just to see how big it is, to be able to paint an accurate preview
+//
+// We delete it again, and if the user finally really creates the module
+// we recreate it.
+
+ mwidget->unselectAll();
+
+ Module *newModule = mwidget->theStructure()->createModule(minfo);
+ width = newModule->width();
+ height = newModule->height();
+ newModule->setSelected(true);
+
+ mwidget->theStructure()->deleteSelected();
+}
+
+void CreateModuleTool::performCreate(int x, int y)
+{
+ mwidget->unselectAll();
+ Module *newModule = mwidget->theStructure()->createModule(minfo);
+ newModule->setSelected(true);
+ newModule->move(x, y);
+
+ if(!mwidget->insertModule(newModule))
+ mwidget->theStructure()->deleteSelected();
+}
+
+CreateModuleTool::CreateModuleTool(ModuleWidget *mwidget,
+ const Arts::ModuleInfo& minfo) : CreateTool(mwidget)
+{
+ this->minfo = minfo;
+}
+
+CreateModuleTool::~CreateModuleTool()
+{
+}
+
+// interface creation
+
+void CreateInterfaceTool::estimateSize()
+{
+ vector<Arts::PortType>::iterator pi;
+
+ int input_width = 0;
+ int output_width = 0;
+
+ for(pi = minfo.ports.begin(); pi != minfo.ports.end(); ++pi)
+ {
+ if(pi->direction == Arts::input)
+ input_width++;
+
+ if(pi->direction == Arts::output)
+ output_width++;
+ }
+ width = max(input_width, output_width);
+ height = 5;
+}
+
+void CreateInterfaceTool::performCreate(int x, int y)
+{
+ vector<std::string>::iterator pni;
+ vector<Arts::PortType>::iterator pi;
+
+ mwidget->theStructure()->addInheritedInterface(minfo.name.c_str());
+
+ int input_width = 0;
+ int output_width = 0;
+
+ for(pi = minfo.ports.begin(), pni = minfo.portnames.begin();
+ pi != minfo.ports.end(); ++pi, pni++)
+ {
+ StructurePort *port = 0;
+ /*
+ * watch out: input ports (as in ports that accept data) are on the lower
+ * side of the structure, as the data flows out trough them ;)
+ */
+ if(pi->direction == Arts::input)
+ {
+ port = mwidget->insertPort(*pi, x + input_width, y + 4);
+ input_width++;
+ }
+ else if(pi->direction == Arts::output)
+ {
+ port = mwidget->insertPort(*pi, x + output_width, y);
+ output_width++;
+ }
+
+ assert(port);
+ port->rename(pni->c_str());
+ port->inheritedInterface(minfo.name.c_str());
+ }
+}
+
+CreateInterfaceTool::CreateInterfaceTool(ModuleWidget *mwidget,
+ const Arts::ModuleInfo& minfo) : CreateTool(mwidget)
+{
+ this->minfo = minfo;
+
+ vector<Arts::PortType>::iterator pi;
+ for(pi = this->minfo.ports.begin(); pi != this->minfo.ports.end(); ++pi)
+ {
+ /* reverse since we're inside the interface, not outside */
+ if(pi->direction == Arts::input)
+ pi->direction = Arts::output;
+ else if(pi->direction == Arts::output)
+ pi->direction = Arts::input;
+ }
+}
+
+CreateInterfaceTool::~CreateInterfaceTool()
+{
+}
+
+// port creation
+
+void CreatePortTool::estimateSize()
+{
+ width = height = 1;
+}
+
+void CreatePortTool::performCreate(int x, int y)
+{
+ mwidget->insertPort(type, x, y);
+}
+
+CreatePortTool::CreatePortTool(ModuleWidget *mwidget,
+ const Arts::PortType& type) : CreateTool(mwidget)
+{
+ this->type = type;
+}
+
+MoveComponentsTool::MoveComponentsTool(ModuleWidget *widget, QMouseEvent *e)
+ : MWidgetTool(widget),
+ lastPos(e->pos())
+{
+}
+
+void MoveComponentsTool::mousePressEvent(QMouseEvent *e)
+{
+}
+
+void MoveComponentsTool::mouseMoveEvent(QMouseEvent *e)
+{
+ int dx = (e->x() - lastPos.x())/mwidget->cellsize;
+ int dy = (e->y() - lastPos.y())/mwidget->cellsize;
+
+ if(dx == 0 && dy == 0)
+ return;
+
+ std::list<StructureComponent *>::iterator i;
+ std::list<StructureComponent *> *ComponentList = mwidget->structure->getComponentList();
+
+ for(i = ComponentList->begin();i != ComponentList->end();++i)
+ {
+ StructureComponent *c = *i;
+ if(c->selected() && !mwidget->hasSpace(c, c->x() + dx, c->y() + dy, true))
+ return;
+ }
+
+ mwidget->beginUpdate();
+ for(i = ComponentList->begin();i != ComponentList->end();++i)
+ {
+ StructureComponent *c = *i;
+ if(c->selected())
+ c->move(c->x() + dx, c->y() + dy);
+ }
+ mwidget->endUpdate();
+
+ lastPos.setX(lastPos.x() + dx*mwidget->cellsize);
+ lastPos.setY(lastPos.y() + dy*mwidget->cellsize);
+ mwidget->reRoute();
+}
+
+void MoveComponentsTool::mouseReleaseEvent(QMouseEvent *e)
+{
+ mwidget->leaveTool(this, true);
+}
+
+ConnectPortsTool::ConnectPortsTool(ModuleWidget *widget, ModulePort *connectingPort)
+ : MWidgetTool(widget),
+ connectingPort(connectingPort)
+{
+ firstPos = mwidget->portPos(connectingPort) + connectingPort->clickrect.center();
+}
+
+void ConnectPortsTool::mousePressEvent(QMouseEvent *e)
+{
+}
+
+void ConnectPortsTool::mouseMoveEvent(QMouseEvent *e)
+{
+ QPainter painter(mwidget);
+ painter.setPen(Qt::white);
+ mwidget->repaint(QRect(firstPos, lastPos).normalize());
+ painter.drawLine(firstPos, e->pos());
+ lastPos = e->pos();
+}
+
+void ConnectPortsTool::mouseReleaseEvent(QMouseEvent *e)
+{
+ StructureComponent *component;
+ ModulePort *otherPort;
+ mwidget->findAt(e->x(), e->y(), component, otherPort);
+ if(otherPort && (otherPort!= connectingPort))
+ {
+ // user is trying to close a connection
+ if(connectingPort->direction == otherPort->direction)
+ {
+ KMessageBox::sorry(mwidget,
+ i18n("You can only connect an IN-port with an OUT-port,\n"
+ "not two ports with the same direction."));
+ }
+ else
+ {
+ if(connectingPort->direction == ModulePort::in)
+ {
+ if(otherPort->PortDesc.connectTo(connectingPort->PortDesc))
+ mwidget->reRoute();
+ } else {
+ if(connectingPort->PortDesc.connectTo(otherPort->PortDesc))
+ mwidget->reRoute();
+ }
+ }
+ }
+ mwidget->repaint(QRect(firstPos, lastPos).normalize());
+ mwidget->leaveTool(this);
+}
diff --git a/arts/builder/createtool.h b/arts/builder/createtool.h
new file mode 100644
index 00000000..3796e018
--- /dev/null
+++ b/arts/builder/createtool.h
@@ -0,0 +1,132 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef _CREATETOOL_H
+#define _CREATETOOL_H
+
+#include <qwidget.h>
+#include <qcursor.h>
+
+#include "structure.h"
+#include "module.h"
+#include "scomponent.h"
+
+class ModulePort;
+class ModuleWidget;
+
+class MWidgetTool
+{
+protected:
+ ModuleWidget *mwidget;
+
+public:
+ MWidgetTool(ModuleWidget *mwidget);
+ virtual ~MWidgetTool();
+
+ virtual void mousePressEvent(QMouseEvent *e) = 0;
+ virtual void mouseMoveEvent(QMouseEvent *e) = 0;
+ virtual void mouseReleaseEvent(QMouseEvent *e) = 0;
+};
+
+class CreateTool: public MWidgetTool
+{
+protected:
+ QCursor oldCursor;
+ bool oldMouseTracking;
+ QRect componentRect;
+ int width, height;
+
+public:
+ CreateTool(ModuleWidget *mwidget);
+ virtual ~CreateTool();
+
+ virtual void estimateSize() = 0;
+ virtual void performCreate(int x, int y) = 0;
+
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+};
+
+class CreateModuleTool: public CreateTool
+{
+protected:
+ Arts::ModuleInfo minfo;
+
+public:
+ CreateModuleTool(ModuleWidget *mwidget, const Arts::ModuleInfo& minfo);
+ ~CreateModuleTool();
+
+ void estimateSize();
+ void performCreate(int x, int y);
+};
+
+class CreateInterfaceTool: public CreateTool
+{
+protected:
+ Arts::ModuleInfo minfo;
+
+public:
+ CreateInterfaceTool(ModuleWidget *mwidget, const Arts::ModuleInfo& minfo);
+ ~CreateInterfaceTool();
+
+ void estimateSize();
+ void performCreate(int x, int y);
+};
+
+class CreatePortTool: public CreateTool
+{
+protected:
+ Arts::PortType type;
+
+public:
+ CreatePortTool(ModuleWidget *widget, const Arts::PortType& type);
+
+ void estimateSize();
+ void performCreate(int x, int y);
+};
+
+class MoveComponentsTool: public MWidgetTool
+{
+ QPoint lastPos;
+
+public:
+ MoveComponentsTool(ModuleWidget *widget, QMouseEvent *e);
+
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+};
+
+class ConnectPortsTool: public MWidgetTool
+{
+ ModulePort *connectingPort;
+ QPoint firstPos, lastPos;
+
+public:
+ ConnectPortsTool(ModuleWidget *widget, ModulePort *connectingPort);
+
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+};
+
+#endif
diff --git a/arts/builder/dirmanager.cpp b/arts/builder/dirmanager.cpp
new file mode 100644
index 00000000..80a2e0ff
--- /dev/null
+++ b/arts/builder/dirmanager.cpp
@@ -0,0 +1,96 @@
+ /*
+
+ Copyright (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 <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <qfile.h>
+
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <klocale.h>
+
+#include "dirmanager.h"
+
+using namespace std;
+
+const char *DirManager::mapDir()
+{
+ static char *d = 0;
+
+ if(!d) d = directory("/maps",i18n("instrument map files"));
+ return d;
+}
+
+const char *DirManager::sessionDir()
+{
+ static char *d = 0;
+
+ if(!d) d = directory("/sessions",
+ i18n("sessions (save files of the positions of all sliders/buttons)"));
+
+ return d;
+}
+
+const char *DirManager::structureDir()
+{
+ static char *d = 0;
+
+ if(!d) d = directory("/structures",i18n("structures (signal flow graphs)"));
+ return d;
+}
+
+const char *DirManager::baseDir()
+{
+ static char *d = 0;
+
+ if(!d) d = directory("",i18n("all aRts files/folders"));
+ return d;
+}
+
+char *DirManager::directory(const char *subdir, const QString &desc)
+{
+ const char *home = getenv("HOME");
+
+ if(home == 0) return strdup("");
+
+ QCString dirname = QCString(home) + "/arts" + subdir;
+
+ struct stat buf;
+ if(stat(dirname.data(), &buf) == -1)
+ {
+ QString message;
+ QString dir = QFile::decodeName(dirname);
+ message = i18n("You need the folder %1.\n"
+ "It will be used to store %2.\nShould I create it now?")
+ .arg(dir).arg(desc);
+
+ if(KMessageBox::questionYesNo(0,message,i18n("aRts Folder Missing"),i18n("Create Folder"),i18n("Do Not Create"))
+ == KMessageBox::Yes)
+ {
+ KStandardDirs::makeDir(dir);
+ }
+ }
+
+ return strdup(dirname.data());
+}
diff --git a/arts/builder/dirmanager.h b/arts/builder/dirmanager.h
new file mode 100644
index 00000000..6ae070de
--- /dev/null
+++ b/arts/builder/dirmanager.h
@@ -0,0 +1,34 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef _DIRMANAGER_H_
+#define _DIRMANAGER_H_
+
+class DirManager {
+protected:
+ static char *directory(const char *subdir, const QString& desc);
+public:
+ static const char *mapDir();
+ static const char *sessionDir();
+ static const char *structureDir();
+ static const char *baseDir();
+};
+#endif
diff --git a/arts/builder/drawutils.cpp b/arts/builder/drawutils.cpp
new file mode 100644
index 00000000..144a8016
--- /dev/null
+++ b/arts/builder/drawutils.cpp
@@ -0,0 +1,39 @@
+ /*
+
+ Copyright (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 "drawutils.h"
+
+QString DrawUtils::cropText(QPainter *p, QString text, int maxlen, int& textwidth)
+{
+ QString label = text;
+
+ while(p->fontMetrics().width(label) > maxlen && label.length() > 0) {
+ int i = label.find('_');
+
+ if(i != -1)
+ label = label.mid(i+1);
+ else
+ label = label.left(label.length() - 1);
+ }
+
+ textwidth = p->fontMetrics().width(label);
+ return label;
+}
diff --git a/arts/builder/drawutils.h b/arts/builder/drawutils.h
new file mode 100644
index 00000000..3b1a6282
--- /dev/null
+++ b/arts/builder/drawutils.h
@@ -0,0 +1,31 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef __DRAWUTILS_H__
+#define __DRAWUTILS_H__
+
+#include <qpainter.h>
+
+class DrawUtils {
+public:
+ static QString cropText(QPainter *p, QString text, int maxlen, int& textwidth);
+};
+#endif
diff --git a/arts/builder/execdlg.cpp b/arts/builder/execdlg.cpp
new file mode 100644
index 00000000..2186d1f5
--- /dev/null
+++ b/arts/builder/execdlg.cpp
@@ -0,0 +1,201 @@
+ /*
+
+ Copyright (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 <qfile.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qlineedit.h>
+
+#include <kbuttonbox.h>
+#include <kfiledialog.h>
+#include <kseparator.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kstdguiitem.h>
+
+#include <unistd.h>
+#include "execdlg.h"
+#include "dirmanager.h"
+#include <arts/debug.h>
+#include <qpushbutton.h>
+
+#ifndef KDE_USE_FINAL
+static void min_size(QWidget *w) {
+ w->setMinimumSize(w->sizeHint());
+}
+#endif
+
+ExecDlg::ExecDlg(QWidget *parent, ExecutableStructure *structure)
+ :QDialog(parent,"X")
+/*, TRUE)*/
+{
+ this->structure = structure;
+
+ setCaption(i18n("aRts Module Execution"));
+
+ mainlayout = new QVBoxLayout(this);
+
+// caption label: "Synthesis running..."
+
+ mainlayout->addSpacing(5);
+ QLabel *captionlabel = new QLabel(this);
+ QFont labelfont(captionlabel->font());
+ labelfont.setPointSize(labelfont.pointSize()*3/2);
+ captionlabel->setFont(labelfont);
+ captionlabel->setText(QString(" ")+i18n("Synthesis running...")+QString(" "));
+ captionlabel->setAlignment(AlignCenter);
+ min_size(captionlabel);
+ mainlayout->addWidget(captionlabel);
+
+ cpuusagelabel = new QLabel(this);
+ cpuusagelabel->setText(i18n("CPU usage: unknown"));
+
+ cpuusagetimer = new QTimer( this );
+ connect( cpuusagetimer, SIGNAL(timeout()),
+ this, SLOT(updateCpuUsage()) );
+ connect( cpuusagetimer, SIGNAL(timeout()),
+ this, SLOT(guiServerTick()) );
+ cpuusagetimer->start( 2000, false );
+
+ min_size(cpuusagelabel);
+ mainlayout->addWidget(cpuusagelabel);
+
+// ruler above the sliderlayout
+
+ mainlayout->addSpacing(5);
+ KSeparator* sep = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(sep);
+ mainlayout->addSpacing(5);
+
+// sliders, controlpanels
+
+ sliderlayout = new QVBoxLayout;
+ mainlayout->addLayout(sliderlayout);
+
+#if 0 /* PORT */
+ this->GUIServer = GUIServer;
+ GUIServer->setGlobalParent(this);
+ GUIServer->setGlobalLayout(sliderlayout);
+#endif
+
+// hruler below the sliderlayout
+
+ mainlayout->addSpacing(5);
+ sep = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(sep);
+ mainlayout->addSpacing(5);
+
+// buttons
+
+ QHBoxLayout *buttonlayout = new QHBoxLayout;
+ mainlayout->addSpacing(5);
+ mainlayout->addLayout(buttonlayout);
+ mainlayout->addSpacing(5);
+
+ buttonlayout->addSpacing(5);
+ KButtonBox *bbox = new KButtonBox(this);
+
+ bbox->addButton(KStdGuiItem::help(), this, SLOT( help() ));
+
+ bbox->addStretch(1);
+
+ QButton *savebutton = bbox->addButton(KStdGuiItem::saveAs());
+ connect( savebutton, SIGNAL( clicked() ), SLOT(saveSession() ) );
+
+ QButton *okbutton = bbox->addButton(KStdGuiItem::ok());
+ connect( okbutton, SIGNAL( clicked() ), SLOT(accept() ) );
+
+ bbox->layout();
+ //min_size(bbox);
+
+ buttonlayout->addWidget(bbox);
+ buttonlayout->addSpacing(5);
+
+// mainlayout->freeze();
+}
+
+void ExecDlg::start()
+{
+ mainlayout->freeze();
+}
+
+void ExecDlg::guiServerTick()
+{
+#if 0 /* TODO:PORT */
+ GUIServer->tick();
+#endif
+}
+
+void ExecDlg::updateCpuUsage()
+{
+#if 0 /* TODO:PORT */
+ char cpuusage[100];
+
+ ArtsCorba::Status s = Synthesizer->getStatus();
+ if(s.halted)
+ {
+ cpuusagetimer->stop();
+ accept();
+ PortableKDE::KMsgSorry(this,i18n("Your synthesis has been interrupted due to excessive CPU load."));
+ /*
+ KMsgBox::message(this,i18n("Error"),
+ i18n("Your synthesis has been interrupted due to excessive CPU load."),
+ KMsgBox::STOP);
+ */
+ // warning: this is invalid after accept();
+ return;
+ }
+ sprintf(cpuusage,"%s%3.2f%%",
+ (const char *)i18n("CPU usage: "),s.cpu_usage*100);
+
+ cpuusagelabel->setText(cpuusage);
+
+ if(!structure->isExecuting()) accept();
+ // warning: this is invalid after accept();
+#endif
+}
+
+void ExecDlg::done( int r )
+{
+ structure->stopExecute();
+ QDialog::done(r);
+ emit ready();
+}
+
+void ExecDlg::saveSession()
+{
+ chdir(DirManager::sessionDir());
+
+ QString filename = KFileDialog::getSaveFileName(0,"*.arts-session",this);
+ if(!filename.isEmpty())
+ {
+ arts_debug("save... %s",filename.local8Bit().data());
+ structure->saveSession(QFile::encodeName(filename));
+ }
+}
+
+void ExecDlg::help()
+{
+ KApplication::kApplication()->invokeHelp("", "karts");
+}
+#include "execdlg.moc"
diff --git a/arts/builder/execdlg.h b/arts/builder/execdlg.h
new file mode 100644
index 00000000..47db3562
--- /dev/null
+++ b/arts/builder/execdlg.h
@@ -0,0 +1,54 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef __EXECDLG_H_
+#define __EXECDLG_H_
+
+#include "structure.h"
+#include <qdialog.h>
+#include <qtimer.h>
+#include <qlabel.h>
+#include <qscrollbar.h>
+#include <qlayout.h>
+
+class ExecDlg :public QDialog {
+ Q_OBJECT
+public:
+ QTimer *cpuusagetimer;
+ QLabel *cpuusagelabel;
+ QVBoxLayout *mainlayout,*sliderlayout;
+ ExecutableStructure *structure;
+
+ void start();
+ void done(int r);
+ ExecDlg(QWidget *parent, ExecutableStructure *structure);
+
+protected slots:
+ void updateCpuUsage();
+ void guiServerTick();
+ void saveSession();
+ void help();
+
+signals:
+ void ready();
+};
+
+#endif
diff --git a/arts/builder/interfacedlg.cpp b/arts/builder/interfacedlg.cpp
new file mode 100644
index 00000000..b0cc5970
--- /dev/null
+++ b/arts/builder/interfacedlg.cpp
@@ -0,0 +1,178 @@
+ /*
+
+ Copyright (C) 1998-2001 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 "interfacedlg.h"
+#include "structureport.h"
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlistbox.h>
+#include <kbuttonbox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kseparator.h>
+#include <klocale.h>
+#include <qlineedit.h>
+#include <stdio.h>
+#include <arts/debug.h>
+#include <arts/core.h>
+#include <arts/dispatcher.h>
+#include <qpushbutton.h>
+#include <kstdguiitem.h>
+
+using namespace std;
+
+InterfaceDlg::InterfaceDlg(QWidget *parent) :QDialog(parent,"Props", TRUE)
+{
+ setCaption(i18n("aRts: Structureport View"));
+
+ QVBoxLayout *mainlayout = new QVBoxLayout(this);
+ //QHBoxLayout *contentslayout = new QHBoxLayout;
+
+// object type
+/*
+ mainlayout->addSpacing(5);
+ QLabel *objectlabel = new QLabel(this);
+ QFont labelfont(objectlabel->font());
+ labelfont.setPointSize(labelfont.pointSize()*3/2);
+ objectlabel->setFont(labelfont);
+ objectlabel->setText(QString(" ")+i18n("Object type: ")+QString(port->owner->name())+QString(" "));
+ objectlabel->setAlignment(AlignCenter);
+ min_size(objectlabel);
+ mainlayout->addWidget(objectlabel);
+*/
+
+// port description
+
+/*
+ mainlayout->addSpacing(5);
+ QLabel *portlabel = new QLabel(this);
+ labelfont.setPointSize(labelfont.pointSize()*4/5);
+ portlabel->setFont(labelfont);
+ portlabel->setText(i18n("Port description: ")+ port->description);
+ min_size(portlabel);
+ portlabel->setAlignment(AlignCenter);
+ mainlayout->addWidget(portlabel);
+
+ int labelwidth = imax(portlabel->sizeHint().width(),objectlabel->sizeHint().width());
+
+ portlabel->setMinimumWidth(labelwidth);
+ objectlabel->setMinimumWidth(labelwidth);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler);
+ mainlayout->addSpacing(5);
+ mainlayout->addLayout(contentslayout);
+*/
+// list
+
+ listbox = new QListBox(this);
+
+ update();
+
+ listbox->setMinimumSize(340,400);
+ mainlayout->addWidget(listbox);
+ connect( listbox, SIGNAL( doubleClicked ( QListBoxItem *)), this,
+ SLOT(accept()));
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler2 = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler2);
+
+// buttons
+
+ QHBoxLayout *buttonlayout = new QHBoxLayout;
+ mainlayout->addSpacing(5);
+ mainlayout->addLayout(buttonlayout);
+ mainlayout->addSpacing(5);
+
+ buttonlayout->addSpacing(5);
+ KButtonBox *bbox = new KButtonBox(this);
+
+ bbox->addButton(KStdGuiItem::help(), this, SLOT( help() ));
+ bbox->addStretch(1);
+
+ QButton *okbutton = bbox->addButton(KStdGuiItem::ok());
+ connect( okbutton, SIGNAL( clicked() ), SLOT(accept() ) );
+
+ QButton *cancelbutton = bbox->addButton(KStdGuiItem::cancel());
+ connect( cancelbutton, SIGNAL( clicked() ), SLOT(reject() ) );
+
+ bbox->layout();
+ //min_size(bbox);
+
+ buttonlayout->addWidget(bbox);
+ buttonlayout->addSpacing(5);
+
+ //mainlayout->activate();
+ mainlayout->freeze();
+}
+
+string InterfaceDlg::interfaceName()
+{
+ if(listbox->currentItem() != -1)
+ {
+ string s = listbox->text(listbox->currentItem()).local8Bit().data();
+ string::iterator j = s.begin();
+ while(*j == ' ') j++;
+ return string(j, s.end());
+ }
+ return "";
+}
+
+void InterfaceDlg::raise()
+{
+}
+
+void InterfaceDlg::lower()
+{
+}
+
+void InterfaceDlg::rename()
+{
+}
+
+void InterfaceDlg::update(const string& interface, const string& indent)
+{
+ listbox->insertItem((indent + interface).c_str());
+
+ vector<string> *children = Arts::Dispatcher::the()->interfaceRepo().queryChildren(interface);
+ for (vector<string>::iterator ci = children->begin(); ci != children->end(); ++ci)
+ update(ci->c_str(), indent+" ");
+ delete children;
+}
+
+void InterfaceDlg::update()
+{
+ update("Arts::Object", "");
+}
+
+void InterfaceDlg::help()
+{
+ KApplication::kApplication()->invokeHelp("", "karts");
+}
+
+#include "interfacedlg.moc"
diff --git a/arts/builder/interfacedlg.h b/arts/builder/interfacedlg.h
new file mode 100644
index 00000000..1cfd6a60
--- /dev/null
+++ b/arts/builder/interfacedlg.h
@@ -0,0 +1,52 @@
+ /*
+
+ Copyright (C) 1998-2001 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.
+
+ */
+
+#ifndef __INTERFACEDLG_H_
+#define __INTERFACEDLG_H_
+
+#include "structure.h"
+#include "structureport.h"
+#include <qdialog.h>
+#include <qlistbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <vector>
+
+class InterfaceDlg :public QDialog {
+ Q_OBJECT
+protected:
+ QListBox *listbox;
+
+public:
+ InterfaceDlg(QWidget *parent);
+
+ std::string interfaceName();
+ void update(const std::string& interface, const std::string& indent);
+ void update();
+
+public slots:
+ void raise();
+ void lower();
+ void rename();
+ void help();
+};
+
+#endif
diff --git a/arts/builder/main.cpp b/arts/builder/main.cpp
new file mode 100644
index 00000000..9c6d4277
--- /dev/null
+++ b/arts/builder/main.cpp
@@ -0,0 +1,958 @@
+/*
+
+ Copyright (C) 1998 - 2000 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 "main.h"
+
+#include "structure.h"
+#include "structureport.h"
+#include "menumaker.h"
+#include "session.h"
+#include "dirmanager.h"
+#include "moduleinfo.h"
+#include "qiomanager.h"
+#include "artsversion.h"
+#include "propertypanel.h"
+#include "module.h"
+#include "autorouter.h"
+#include "portposdlg.h"
+#include "interfacedlg.h"
+#include "execdlg.h"
+#include "retrievedlg.h"
+
+#include "config.h"
+
+#include <kdebug.h>
+#include <arts/debug.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <kstdaccel.h>
+#include <kfiledialog.h>
+#include <ksavefile.h>
+#include <kmessagebox.h>
+#include <kaboutdata.h>
+#include <kstandarddirs.h>
+#include <kartsserver.h>
+#include <qfile.h>
+#include <qpopupmenu.h>
+
+#include <soundserver.h>
+
+#include <list>
+#include <iostream>
+
+#include <unistd.h>
+#include <string.h> // strerror always here?
+//#include <errno.h>
+
+
+using namespace std;
+
+/*************************************************************/
+
+class ArtsBuilderApp :public KApplication
+{
+protected:
+ ArtsBuilderWindow *mainWindow;
+
+public:
+ ArtsBuilderApp();
+ ArtsBuilderApp(QString filename);
+ void start();
+ void end();
+};
+
+/*************************************************************/
+
+ArtsBuilderWindow::ArtsBuilderWindow(const char *name)
+ : KDockMainWindow(0, name),
+ mainDock(0),
+ modulewidget(0),
+ propertyDock(0),
+ propertyPanel(0),
+ menumaker(0),
+ structure(0),
+ execDlg(0)
+{
+#if 0 /* PORT */
+ ModuleBroker = Synthesizer->moduleBroker();
+ assert(ModuleBroker);
+
+//---- publish my widgets on the server ----
+
+ GUIServer = new GUIServer_impl(ModuleBroker, Synthesizer);
+ arts_debug("GUIServer:\n%s", ArtsOrb->object_to_string(GUIServer));
+ GUIServer->incRef();
+
+//---- trigger autoloading of all structures that are present in my dirs ----
+
+ list<string> datadirs = PortableKDE::globalDirs("data");
+ list<string>::iterator it;
+
+ for(it = datadirs.begin(); it != datadirs.end(); ++it)
+ {
+ string common = *it;
+ common += "artsbuilder";
+ if(chdir(common.c_str()) == 0)
+ ModuleBroker->addPublishingPath(common.c_str());
+ }
+ /*
+ string common = (const char *)PortableKDE::globalDir("data");
+ common += "/artsbuilder";
+ arts_debug("%s", common.c_str());
+ if(chdir(common.c_str()) == 0)
+ ModuleBroker->addPublishingPath(common.c_str());
+ */
+
+ // just make sure that the mapsDir exists
+ (void)DirManager::mapDir();
+
+ if(chdir(DirManager::structureDir()) == 0) // retry
+ {
+ ModuleBroker->addPublishingPath(DirManager::structureDir());
+ Synthesizer->addArtsDirectory(DirManager::baseDir());
+
+ }
+#endif
+
+ arts_debug("PORT: structure");
+ structure = new Structure();
+ arts_debug("PORT: structure ok");
+ //ModuleList = structure->getModuleList();
+
+ mainDock = createDockWidget("mainDockWidget", 0, 0, "main_dock_widget");
+
+ arts_debug("PORT: modulewidget");
+ modulewidget = new ModuleWidget(structure, mainDock, "mwidget");
+ mainDock->setWidget(modulewidget);
+ connect(modulewidget, SIGNAL(modified(bool)), SLOT(setModified(bool)));
+ arts_debug("PORT: modulewidget ok");
+
+ // allow others to dock to the 4 sides
+ mainDock->setDockSite(KDockWidget::DockCorner);
+ // forbit docking abilities of module widget itself
+ mainDock->setEnableDocking(KDockWidget::DockNone);
+
+ setView(mainDock);
+ setMainDockWidget(mainDock);
+
+ propertyDock = createDockWidget("propertyDock", 0, 0, i18n("Port Properties"));
+
+ propertyPanel = new PropertyPanel(propertyDock, "ppanel");
+
+ propertyDock->setWidget(propertyPanel);
+ propertyDock->manualDock(mainDock, // dock target
+ KDockWidget::DockBottom, // dock site
+ 80); // relation target/this (in percent)
+
+ // selection
+ connect(modulewidget, SIGNAL(portSelected(ModulePort *)),
+ propertyPanel, SLOT (setSelectedPort(ModulePort *)));
+ connect(propertyPanel, SIGNAL(portSelected(ModulePort *)),
+ modulewidget, SLOT (selectPort(ModulePort *)));
+ connect(modulewidget, SIGNAL(componentSelected(StructureComponent *)),
+ propertyPanel, SLOT (setSelectedComponent(StructureComponent *)));
+
+ // connection
+ connect(propertyPanel, SIGNAL(startConnection(ModulePort *)),
+ modulewidget, SLOT (startConnection(ModulePort *)));
+
+ // port properties changed
+ connect(propertyPanel, SIGNAL(portPropertiesChanged(ModulePort *)),
+ modulewidget, SLOT (portPropertiesChanged(ModulePort *)));
+
+ arts_debug("PORT: setcanvas");
+ structure->setCanvas(modulewidget);
+ arts_debug("PORT: setcanvas ok");
+
+ mbroker_updateCount = 0;
+
+ arts_debug("PORT: menumaker");
+ menumaker = new MenuMaker(new KActionMenu(i18n("Modules"), actionCollection(), "modulesmenu"));
+ //menumaker->addCategory("&Gui", "Gui_");
+ menumaker->addCategory(i18n("&Synthesis"), "Arts::Synth_");
+ menumaker->addCategory(i18n("&Synthesis/&Arithmetic + Mixing"), "Arts::Synth_ADD$");
+ menumaker->addCategory(i18n("&Synthesis/&Arithmetic + Mixing"), "Arts::Synth_AUTOPANNER$");
+ menumaker->addCategory(i18n("&Synthesis/&Arithmetic + Mixing"), "Arts::Synth_MUL$");
+ menumaker->addCategory(i18n("&Synthesis/&Arithmetic + Mixing"), "Arts::Synth_DIV$");
+ menumaker->addCategory(i18n("&Synthesis/&Arithmetic + Mixing"), "Arts::Synth_MULTI_ADD$");
+ menumaker->addCategory(i18n("&Synthesis/&Arithmetic + Mixing"), "Arts::Synth_XFADE$");
+ menumaker->addCategory(i18n("&Synthesis/&Busses"), "Arts::Synth_BUS_");
+ menumaker->addCategory(i18n("&Synthesis/&Delays"), "Arts::Synth_DELAY$");
+ menumaker->addCategory(i18n("&Synthesis/&Delays"), "Arts::Synth_CDELAY$");
+ menumaker->addCategory(i18n("&Synthesis/&Envelopes"), "Arts::Synth_PSCALE$");
+ menumaker->addCategory(i18n("&Synthesis/&Envelopes"), "Arts::Synth_ENVELOPE_");
+ menumaker->addCategory(i18n("&Synthesis/Effe&cts"), "Arts::Synth_FREEVERB$");
+ menumaker->addCategory(i18n("&Synthesis/Effe&cts"), "Arts::Synth_FX_");
+ menumaker->addCategory(i18n("&Synthesis/Effe&cts"), "Arts::Synth_PITCH_SHIFT$");
+ menumaker->addCategory(i18n("&Synthesis/Effe&cts"), "Arts::Synth_TREMOLO$");
+ menumaker->addCategory(i18n("&Synthesis/&Filters"), "Arts::Synth_ATAN_SATURATE$");
+ menumaker->addCategory(i18n("&Synthesis/&Filters"), "Arts::Synth_BRICKWALL_LIMITER$");
+ menumaker->addCategory(i18n("&Synthesis/&Filters"), "Arts::Synth_MOOG_VCF");
+ menumaker->addCategory(i18n("&Synthesis/&Filters"), "Arts::Synth_SHELVE_CUTOFF$");
+ menumaker->addCategory(i18n("&Synthesis/&Filters"), "Arts::Synth_RC$");
+ menumaker->addCategory(i18n("&Synthesis/&Filters"), "Arts::Synth_STD_EQUALIZER$");
+ menumaker->addCategory(i18n("&Synthesis/&Midi + Sequencing"), "Arts::Synth_MIDI");
+ menumaker->addCategory(i18n("&Synthesis/&Midi + Sequencing"), "Arts::Interface_MIDI");
+ menumaker->addCategory(i18n("&Synthesis/&Midi + Sequencing"), "Arts::Synth_SEQUENCE$");
+ menumaker->addCategory(i18n("&Synthesis/&Midi + Sequencing"), "Arts::Synth_SEQUENCE_FREQ$");
+ menumaker->addCategory(i18n("&Synthesis/&Midi + Sequencing"), "Arts::Synth_STRUCT_KILL$");
+ menumaker->addCategory(i18n("&Synthesis/Sam&ples "), "Arts::Synth_PLAY_");
+ menumaker->addCategory(i18n("&Synthesis/&Sound IO"), "Arts::Synth_AMAN_");
+ menumaker->addCategory(i18n("&Synthesis/&Sound IO"), "Arts::Synth_CAPTURE_WAV$");
+ menumaker->addCategory(i18n("&Synthesis/&Sound IO"), "Arts::Synth_PLAY$");
+ menumaker->addCategory(i18n("&Synthesis/&Sound IO"), "Arts::Synth_RECORD$");
+ menumaker->addCategory(i18n("&Synthesis/&Sound IO"), "Arts::Synth_FULL_DUPLEX_");
+ menumaker->addCategory(i18n("&Synthesis/&Sound IO"), "Arts::Synth_FILEPLAY");
+ menumaker->addCategory(i18n("&Synthesis/&Tests"), "Arts::Synth_NIL$");
+ menumaker->addCategory(i18n("&Synthesis/&Tests"), "Arts::Synth_DEBUG$");
+ menumaker->addCategory(i18n("&Synthesis/&Tests"), "Arts::Synth_DATA$");
+ menumaker->addCategory(i18n("&Synthesis/&Tests"), "Arts::Synth_MIDI_DEBUG$");
+ menumaker->addCategory(i18n("&Synthesis/&Oscillation && Modulation"), "Arts::Synth_FREQUENCY$");
+ menumaker->addCategory(i18n("&Synthesis/&Oscillation && Modulation"), "Arts::Synth_FM_SOURCE$");
+ menumaker->addCategory(i18n("&Synthesis/&Oscillation && Modulation"), "Arts::Synth_OSC$");
+ menumaker->addCategory(i18n("&Synthesis/&WaveForms"), "Arts::Synth_WAVE_");
+ menumaker->addCategory(i18n("&Synthesis/&WaveForms"), "Arts::Synth_NOISE$");
+ menumaker->addCategory(i18n("&Synthesis/&Internal"), "Arts::Synth_PARAM_");
+
+ menumaker->addCategory(i18n("&Examples"), "example_");
+ menumaker->addCategory(i18n("&Instruments"), "instrument_");
+ menumaker->addCategory(i18n("&Mixer-Elements"), "mixer_element_");
+ menumaker->addCategory(i18n("&Templates"), "template_");
+ menumaker->addCategory(i18n("&Other"), "*");
+ arts_debug("PORT: menumaker ok");
+
+/*
+ m_modules->insertItem(i18n("&Gui"), m_modules_gui);
+ m_modules->insertItem(i18n("&Synthesis"), m_modules_synth);
+ m_modules->insertItem(i18n("&Instruments"), m_modules_instruments);
+ m_modules->insertItem(i18n("&Other"), m_modules_other);
+ */
+
+#if 000
+ connect(menubar, SIGNAL(highlighted(int)), this, SLOT(activateMenu(int)));
+ connect(m_view, SIGNAL(activated(int)), modulewidget, SLOT(setZoom(int)));
+ connect(m_ports, SIGNAL(activated(int)), this, SLOT(addPort(int)));
+ connect(m_file_new, SIGNAL(activated(int)), this, SLOT(fileNew(int)));
+
+ //connect(m_modules, SIGNAL(activated(int)), this, SLOT(addModule(int)));
+ /*
+ connect(m_modules_synth, SIGNAL(activated(int)), this, SLOT(addModule(int)));
+ connect(m_modules_gui, SIGNAL(activated(int)), this, SLOT(addModule(int)));
+ connect(m_modules_instruments, SIGNAL(activated(int)), this, SLOT(addModule(int)));
+ connect(m_modules_other, SIGNAL(activated(int)), this, SLOT(addModule(int)));
+ */
+ connect(kapp, SIGNAL(lastWindowClosed()), this , SLOT(quit()));
+
+ // update the modules menu once for the start
+#endif
+
+ arts_debug("PORT: activatemenu");
+ connect(menumaker, SIGNAL(activated(const char *)), this, SLOT(addModule(const char *)));
+ fillModuleMenu();
+ arts_debug("PORT: activatemenu ok");
+ setupActions();
+
+ createGUI();
+
+ // connect to aboutToShow to correctly show state of dockwidget there:
+ QPopupMenu *viewmenu = (QPopupMenu*)factory()->container("view", this);
+ if (viewmenu)
+ connect(viewmenu, SIGNAL(aboutToShow()), this, SLOT(viewMenuAboutToShow()));
+ else
+ arts_debug("view menu not found!");
+
+ m_filename = QString::null;
+ setModified(false);
+
+ installEventFilter(propertyPanel);
+}
+
+void ArtsBuilderWindow::setupActions()
+{
+ // File menu
+ KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
+
+ (void)new KAction(i18n("Open Session..."), 0, this, SLOT(openSession()),
+ actionCollection(), "file_open_session");
+ KStdAction::open(this, SLOT(open()), actionCollection());
+ (void)new KAction(i18n("Open E&xample..."), Qt::CTRL + Qt::Key_X, this, SLOT(openExample()),
+ actionCollection(), "file_open_example");
+ KStdAction::save(this, SLOT(save()), actionCollection());
+ KStdAction::saveAs(this, SLOT(saveAs()), actionCollection());
+ (void)new KAction(i18n("&Retrieve From Server..."), Qt::CTRL + Qt::Key_R, this, SLOT(retrieve()),
+ actionCollection(), "file_retrieve_from_server");
+ (void)new KAction(i18n("&Execute Structure"), "artsbuilderexecute", Qt::CTRL + Qt::Key_E, this, SLOT(execute()),
+ actionCollection(), "file_execute_structure");
+ (void)new KAction(i18n("&Rename Structure..."), Qt::CTRL + Qt::Key_R, this, SLOT(rename()),
+ actionCollection(), "file_rename_structure");
+ (void)new KAction(i18n("&Publish Structure"), Qt::CTRL + Qt::Key_P, this, SLOT(publish()),
+ actionCollection(), "file_publish_structure");
+ KStdAction::quit(this, SLOT(close()), actionCollection());
+
+ // Edit menu
+ (void)new KAction(i18n("&Delete"), Qt::Key_Delete, modulewidget, SLOT(delModule()),
+ actionCollection(), "edit_delete");
+ KStdAction::selectAll(modulewidget, SLOT(selectAll()), actionCollection());
+
+ // View menu
+ viewPropertiesAction= new KToggleAction(i18n("&Property Panel"), 0,
+ propertyDock, SLOT(changeHideShowState()),
+ actionCollection(), "view_properties");
+ (void)new KAction(i18n("200%"), 0, this, SLOT(viewAt200()),
+ actionCollection(), "view_200");
+ (void)new KAction(i18n("150%"), 0, this, SLOT(viewAt150()),
+ actionCollection(), "view_150");
+ (void)new KAction(i18n("100%"), 0, this, SLOT(viewAt100()),
+ actionCollection(), "view_100");
+ (void)new KAction(i18n("50%"), 0, this, SLOT(viewAt50()),
+ actionCollection(), "view_50");
+
+ // Ports menu
+ (void)new KAction(i18n("Create IN Audio Signal"), 0, this, SLOT(createInAudioSignal()),
+ actionCollection(), "ports_create_in_audio_signal");
+ (void)new KAction(i18n("Create OUT Audio Signal"), 0, this, SLOT(createOutAudioSignal()),
+ actionCollection(), "ports_create_out_audio_signal");
+ (void)new KAction(i18n("Create IN String Property"), 0, this, SLOT(createInStringProperty()),
+ actionCollection(), "ports_create_in_string_property");
+ (void)new KAction(i18n("Create IN Audio Property"), 0, this, SLOT(createInAudioProperty()),
+ actionCollection(), "ports_create_in_audio_property");
+ (void)new KAction(i18n("Implement Interface..."), 0, this, SLOT(addInterface()),
+ actionCollection(), "ports_implement_interface");
+ (void)new KAction(i18n("Change Positions/Names..."), 0, this, SLOT(changePortPositions()),
+ actionCollection(), "ports_change_positions");
+}
+
+void ArtsBuilderWindow::fillModuleMenu()
+{
+ long updateCount = 3; /* PORT: automatic update of menues missing */
+
+ if(updateCount != mbroker_updateCount)
+ {
+ mbroker_updateCount = updateCount;
+ //---- query all available objects ----
+ Arts::TraderQuery query;
+ query.supports("Buildable", "true");
+ vector<Arts::TraderOffer> *offers = query.query();
+
+ menumaker->clear();
+ //m_file_new->clear();
+
+ vector<Arts::TraderOffer>::iterator i;
+ long n = 1; /* TODO:PORT: is this necessary? I think not */
+ for(i = offers->begin(); i != offers->end(); ++i)
+ {
+ Arts::TraderOffer& offer = *i;
+ string name = offer.interfaceName();
+ menumaker->addItem(name.c_str(),n++);
+
+ /* PORT: templates missing
+ if(strncmp(name, "template_", strlen("template_")) == 0)
+ {
+ char *xname = strdup(&name[strlen("template_")]);
+ int x;
+ for(x = 0;xname[x] != 0; x++)
+ if(xname[x] == '_') xname[x] = ' ';
+
+ m_file_new->insertItem(xname, i);
+ }
+ */
+ }
+ delete offers;
+ }
+#if 0
+ if(0) /*item == modules_menu_item) PORT!!! */
+ {
+ long updateCount = ModuleBroker->updateCount();
+
+ // if the contents of the ModukeBroker changed, update our "modules"-Menu
+ if(updateCount != mbroker_updateCount)
+ {
+ mbroker_updateCount = updateCount;
+ //---- query all available objects ----
+ ArtsCorba::StringSeq_var Modules = ModuleBroker->publishedModules();
+ assert(Modules);
+
+ menumaker->clear();
+ m_file_new->clear();
+
+ unsigned long i;
+ for(i = 0; i < Modules->length();i++)
+ {
+ const char *name = (*Modules)[i];
+ menumaker->addItem(name, i);
+
+ if(strncmp(name, "template_", strlen("template_")) == 0)
+ {
+ char *xname = strdup(&name[strlen("template_")]);
+ int x;
+ for(x = 0;xname[x] != 0; x++)
+ if(xname[x] == '_') xname[x] = ' ';
+
+ m_file_new->insertItem(xname, i);
+ }
+ }
+ }
+ }
+#endif
+}
+
+void ArtsBuilderWindow::quit()
+{
+ if(execDlg) return;
+ arts_debug(">> ArtsBuilderWindow::quit() called");
+ kapp->quit();
+ arts_debug("<< leaving ArtsBuilderWindow::quit()");
+}
+
+ArtsBuilderWindow::~ArtsBuilderWindow()
+{
+ delete structure;
+}
+
+void ArtsBuilderWindow::viewMenuAboutToShow()
+{
+ viewPropertiesAction->setChecked(propertyDock->isVisible());
+}
+
+void ArtsBuilderWindow::publish()
+{
+ checkName();
+ structure->publish();
+ KMessageBox::information(this,
+ i18n("The structure has been published as: '%1' on the server.").arg( structure->name().c_str() ));
+}
+
+QString ArtsBuilderWindow::getOpenFilename(const char *pattern, const char *initialDir)
+{
+ arts_debug(">>>>> getOpenFilename");
+ QString filename = KFileDialog::getOpenFileName(initialDir, pattern, this);
+ arts_debug(">>>>> opendlg closed");
+ if(!filename.isEmpty())
+ {
+ arts_debug("open... %s", filename.local8Bit().data());
+
+ // check that the file is ok:
+
+ FILE *infile = fopen(QFile::encodeName(filename), "r");
+
+ if(infile)
+ {
+ fclose(infile);
+ return(filename);
+ }
+ }
+ return QString("");
+}
+
+void ArtsBuilderWindow::fileNew()
+{
+ if(!promptToSave())
+ return;
+
+ propertyPanel->setSelectedComponent(0);
+ structure->clear();
+ modulewidget->reInit();
+ m_filename = QString::null;
+ setModified(false);
+}
+
+void ArtsBuilderWindow::open()
+{
+ if(!promptToSave())
+ return;
+
+ open(getOpenFilename("*.arts", DirManager::structureDir()));
+}
+
+void ArtsBuilderWindow::open(QString filename)
+{
+ if(!promptToSave())
+ return;
+
+ if(!filename.isEmpty())
+ {
+ structure->load(QFile::encodeName(filename));
+ modulewidget->reInit();
+ if(!structure->valid())
+ {
+ KMessageBox::sorry(this,
+ i18n("The structure could not be loaded correctly. Maybe some of\n"
+ "the modules used in the file are not available in this\n"
+ "version of aRts."),
+ i18n("Arts Warning"));
+ }
+ m_filename = filename;
+ setModified(false);
+ setCaption(m_filename);
+ }
+}
+
+void ArtsBuilderWindow::openSession()
+{
+ if(!promptToSave())
+ return;
+
+ QString filename = getOpenFilename("*.arts-session", DirManager::sessionDir());
+
+ if(!filename.isEmpty())
+ {
+ Session *session = new Session();
+ session->loadSession(QFile::encodeName(filename));
+
+ assert(!execDlg);
+ execDlg = new ExecDlg(0, session);
+ assert(execDlg);
+
+ // this will create the widgets that will eventually get into the
+ // execdlg
+ session->startExecute();
+
+ execDlg->start();
+ execDlg->show();
+
+ connect(execDlg, SIGNAL(ready()), this, SLOT(endexecute()));
+
+ hide();
+ // m_filename = filename; FIXME: DOESN'T THIS BELONG HERE?
+ setModified(false);
+ }
+}
+
+void ArtsBuilderWindow::openExample()
+{
+ if(!promptToSave())
+ return;
+
+ QString dir = locate("data", "artsbuilder/examples/");
+ if(!dir)
+ KMessageBox::sorry(
+ this,
+ i18n("Unable to find the examples folder.\nUsing the current folder instead."),
+ i18n("aRts Warning"));
+
+ open(getOpenFilename("*.arts", QFile::encodeName(dir)));
+}
+
+void ArtsBuilderWindow::saveAs()
+{
+ checkName();
+ string defaultname = string(structure->name()) + string(".arts");
+
+ chdir(DirManager::structureDir());
+ KFileDialog *dlg = new KFileDialog(0, "*.arts", this, 0, true /*,false TODO: acceptURLs */);
+
+ dlg->setSelection(defaultname.c_str());
+ dlg->setCaption(i18n("Save As"));
+
+ QString filename;
+ if(dlg->exec() == QDialog::Accepted)
+ filename = dlg->selectedFile();
+
+ delete dlg;
+ // QString filename = KFileDialog::getSaveFileName(0, "*.arts", this);
+ // filename.detach();
+
+ if(!filename.isEmpty())
+ save(filename);
+}
+
+bool ArtsBuilderWindow::save(QString filename)
+{
+ arts_debug("trying to save structure as '%s'", filename.local8Bit().data());
+
+ KSaveFile file(filename);
+
+ if(file.status()) {
+ KMessageBox::sorry(this,
+ i18n("The file '%1' could not be opened for writing: %2")
+ .arg(filename).arg(strerror(file.status())),
+ i18n("aRts Warning"));
+ return false;
+ }
+
+ structure->saveInto(file.fstream());
+
+ if(!file.close()) {
+ KMessageBox::sorry(this,
+ i18n("Saving to file '%1' could not be finished correctly: %2")
+ .arg(filename).arg(strerror(file.status())),
+ i18n("aRts Warning"));
+ return false;
+ }
+
+ // tell the server to rescan for structures
+ Arts::SoundServerV2 server = KArtsServer().server();
+ if(!server.isNull()) server.checkNewObjects();
+
+ m_filename = filename;
+ setModified(false);
+ return true;
+}
+
+void ArtsBuilderWindow::save()
+{
+ if(m_filename.isEmpty())
+ saveAs();
+ else
+ save(m_filename);
+}
+
+void ArtsBuilderWindow::checkName()
+{
+ if(strncmp(structure->name().c_str(), "template_", strlen("template_")) == 0)
+ rename();
+}
+
+void ArtsBuilderWindow::rename()
+{
+ bool ok;
+
+ QString name = KInputDialog::getText( i18n( "Rename Structure" ),
+ i18n( "Enter structure name:" ), structure->name().c_str(), &ok, this );
+ if (ok)
+ {
+ arts_debug("rename OK...");
+ structure->rename(name.local8Bit());
+ }
+
+ setModified(true);
+}
+
+void ArtsBuilderWindow::retrieve()
+{
+ if(!promptToSave())
+ return;
+
+ RetrieveDlg rd(0);
+
+ if(rd.exec())
+ {
+ QString result = rd.result();
+ if(!result.isEmpty())
+ {
+ structure->retrieve(result.local8Bit());
+ modulewidget->reInit();
+ }
+ }
+ // maybe set m_filename to null or sth. here?
+ setModified(true);
+}
+
+void ArtsBuilderWindow::execute()
+{
+ assert(structure);
+ assert(!execDlg);
+ execDlg = new ExecDlg(0, structure);
+ assert(execDlg);
+
+ // this will create the widgets that will eventually get into the
+ // execdlg
+ if(structure->startExecute())
+ {
+ execDlg->start();
+ execDlg->show();
+
+ connect(execDlg, SIGNAL(ready()), this, SLOT(endexecute()));
+
+ hide();
+ }
+ else
+ {
+ delete execDlg;
+ execDlg = 0;
+
+ KMessageBox::sorry(this,
+ i18n("Could not execute your structure. Make sure that the\n"
+ "sound server (artsd) is running.\n"), i18n("aRts Warning"));
+ }
+}
+
+void ArtsBuilderWindow::endexecute()
+{
+ show();
+ assert(execDlg);
+ delete execDlg;
+ // will be done by the execDlg itself now
+ //structure->stopExecute();
+
+ execDlg = 0;
+}
+
+void ArtsBuilderWindow::oldFileNewWhatTheHellDoesItDo(int what)
+{
+ if(!promptToSave())
+ return;
+
+ const char *name = menumaker->findID(what);
+ assert(name);
+ structure->retrieve(name);
+ modulewidget->reInit();
+ setModified(false);
+}
+
+void ArtsBuilderWindow::createInAudioSignal()
+{
+ // data that goes into the structure
+ modulewidget->addPort(Arts::PortType(Arts::output, "float", Arts::conn_stream, false));
+ setModified(true);
+}
+
+void ArtsBuilderWindow::createOutAudioSignal()
+{
+ // data that goes out of the structure
+ modulewidget->addPort(Arts::PortType(Arts::input, "float", Arts::conn_stream, false));
+ setModified(true);
+}
+
+void ArtsBuilderWindow::createInStringProperty()
+{
+ // data that goes into the structure
+ modulewidget->addPort(Arts::PortType(Arts::output, "string", Arts::conn_property, false));
+ setModified(true);
+}
+
+void ArtsBuilderWindow::createInAudioProperty()
+{
+ // data that goes into the structure
+ modulewidget->addPort(Arts::PortType(Arts::output, "float", Arts::conn_property, false));
+ setModified(true);
+}
+
+void ArtsBuilderWindow::changePortPositions()
+{
+ PortPosDlg *ppd = new PortPosDlg(this, structure);
+ ppd->exec();
+ setModified(true);
+ // XXX: delete ppd?
+}
+
+void ArtsBuilderWindow::addInterface()
+{
+ InterfaceDlg *ifd = new InterfaceDlg(this);
+ ifd->exec();
+
+ Arts::ModuleInfo minfo = makeModuleInfo(ifd->interfaceName());
+ if(!minfo.name.empty())
+ modulewidget->addInterface(minfo);
+
+ delete ifd;
+}
+
+void ArtsBuilderWindow::viewAt50()
+{
+ modulewidget->setZoom(50);
+}
+
+void ArtsBuilderWindow::viewAt100()
+{
+ modulewidget->setZoom(100);
+}
+
+void ArtsBuilderWindow::viewAt150()
+{
+ modulewidget->setZoom(150);
+}
+
+void ArtsBuilderWindow::viewAt200()
+{
+ modulewidget->setZoom(200);
+}
+
+void ArtsBuilderWindow::addModule(const char *name)
+{
+ arts_return_if_fail (name != 0);
+
+ arts_debug("addModule(%s)", name);
+ Arts::ModuleInfo minfo = makeModuleInfo(name);
+
+ if(!minfo.name.empty())
+ modulewidget->addModule(minfo);
+#if 0
+ const char *name = menumaker->findID(module);
+ assert(name);
+
+ arts_debug("selected (%s) (module=%d)", name, module);
+
+ ArtsCorba::ModuleBroker_var ModuleBroker = Synthesizer->moduleBroker();
+ ArtsCorba::ModuleInfo_var minfo = ModuleBroker->lookupModule(name);
+
+
+ if(minfo)
+ {
+ modulewidget->addModule(minfo);
+
+/*
+ Module *m = structure->createModule(minfo);
+ modulewidget->addModule(m);
+*/
+ }
+#endif
+ setModified(true);
+}
+
+bool ArtsBuilderWindow::isModified()
+{
+ return modified;
+}
+
+void ArtsBuilderWindow::setModified(bool m)
+{
+ modified = m;
+ setCaption(m_filename, modified);
+ actionCollection()->action(KStdAction::stdName(KStdAction::Save))->setEnabled(modified);
+}
+
+bool ArtsBuilderWindow::queryClose()
+{
+ return promptToSave();
+}
+
+bool ArtsBuilderWindow::promptToSave()
+{
+ bool result;
+ int query;
+
+ if(!isModified())
+ return true;
+
+ query = KMessageBox::warningYesNoCancel(this,
+ i18n("The current structure has been modified.\nWould you like to save it?"), QString::null, KStdGuiItem::save(), KStdGuiItem::discard());
+
+ result = false;
+ switch(query)
+ {
+ case KMessageBox::Yes:
+ save();
+ result = !modified;
+ break;
+ case KMessageBox::No:
+ result = true;
+ setModified(false);
+ break;
+ case KMessageBox::Cancel:
+ break;
+ }
+ return result;
+}
+
+/*************************************************************/
+
+ArtsBuilderApp::ArtsBuilderApp()
+{
+ start();
+}
+
+ArtsBuilderApp::ArtsBuilderApp(QString filename)
+{
+ start();
+ if(QFile::exists(filename))
+ {
+ mainWindow->open(filename);
+ } else {
+ KMessageBox::sorry(0,
+ i18n("The specified file '%1' does not exist.").arg(filename),
+ i18n("aRts Warning"));
+ }
+}
+
+void ArtsBuilderApp::start()
+{
+ arts_debug("PORT: mainWindow");
+ mainWindow = new ArtsBuilderWindow("main");
+
+ arts_debug("PORT: mainWindow ok");
+ mainWindow->resize(680, 500);
+ arts_debug("PORT: mainWindow show");
+ mainWindow->show();
+ arts_debug("PORT: mainWindow show ok");
+
+#if 0 /* PORT */
+ ArtsCorba::ModuleBroker_var ModuleBroker = theSynthesizer->moduleBroker();
+ assert(ModuleBroker);
+#endif
+
+ setTopWidget(mainWindow);
+}
+
+void ArtsBuilderApp::end()
+{
+ delete mainWindow;
+}
+
+/*************************************************************/
+
+static KCmdLineOptions options[] =
+{
+ { "+[file]", I18N_NOOP("Optional .arts file to be loaded"), 0 },
+ KCmdLineLastOption
+};
+
+#ifdef COMMON_BINARY
+int artsbuilder_main(int argc, char **argv)
+#else
+int main(int argc, char **argv)
+#endif
+{
+ KAboutData aboutData("artsbuilder",
+ I18N_NOOP("artsbuilder"),
+ ARTS_VERSION,
+ I18N_NOOP("aRts synthesizer designer"),
+ KAboutData::License_GPL,
+ "(C) 1998-2001, Stefan Westerfeld",
+ I18N_NOOP("The analog real-time synthesizer graphical design tool."),
+ "http://www.arts-project.org/",
+ "submit@bugs.kde.org");
+
+ aboutData.addAuthor("Stefan Westerfeld", I18N_NOOP("Author"), "stefan@twc.de");
+ aboutData.addCredit("Waldo Bastian", 0, "bastian@kde.org");
+ aboutData.addCredit("Jens Hahn", 0, "Jens.Hahn@t-online.de");
+ aboutData.addCredit("Martin Lorenz", 0, "lorenz@ch.tum.de");
+ aboutData.addCredit("Hans Meine", 0, "hans_meine@gmx.net");
+ aboutData.addCredit("Jeff Tranter", 0, "tranter@pobox.com");
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions(options);
+ Arts::QIOManager iomanager;
+ Arts::Dispatcher dispatcher(&iomanager);
+
+ Arts::ObjectManager::the()->provideCapability("kdegui");
+
+ // check for one optional filename argument
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if(args->count() > 1) {
+ args->usage("");
+ }
+ if(args->count() > 0)
+ {
+ ArtsBuilderApp Application(QFile::decodeName(args->arg(0)));
+ args->clear();
+ return Application.exec();
+ } else {
+ ArtsBuilderApp Application;
+ args->clear();
+ return Application.exec();
+ }
+}
+#include "main.moc"
diff --git a/arts/builder/main.h b/arts/builder/main.h
new file mode 100644
index 00000000..f7babc3a
--- /dev/null
+++ b/arts/builder/main.h
@@ -0,0 +1,118 @@
+ /*
+
+ Copyright (C) 1998-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.
+
+ */
+
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#include "mwidget.h"
+
+#include <kdockwidget.h>
+#include <kapplication.h>
+#include <kfiledialog.h>
+#include <ksimpleconfig.h>
+
+#include <list>
+
+class PropertyPanel;
+class Structure;
+class MenuMaker;
+class ExecDlg;
+class KToggleAction;
+
+class ArtsBuilderWindow: public KDockMainWindow
+{
+ Q_OBJECT
+
+protected:
+ KDockWidget* mainDock;
+ ModuleWidget *modulewidget;
+
+ KDockWidget* propertyDock;
+ PropertyPanel *propertyPanel;
+ KToggleAction *viewPropertiesAction;
+
+ MenuMaker *menumaker;
+
+ long mbroker_updateCount;
+ Structure *structure;
+
+ ExecDlg *execDlg;
+
+ QString m_filename;
+ bool modified;
+
+protected:
+ void setupActions();
+
+public:
+ ArtsBuilderWindow(const char *name);
+ ~ArtsBuilderWindow();
+
+ void clear();
+ void checkName();
+ QString getOpenFilename(const char *pattern, const char *initialDir = 0);
+ bool isModified();
+ bool promptToSave();
+ bool queryClose();
+
+public slots:
+ void fillModuleMenu();
+ void viewMenuAboutToShow();
+
+ /* ports menu */
+ void createInAudioSignal();
+ void createOutAudioSignal();
+ void createInStringProperty();
+ void createInAudioProperty();
+ void addInterface();
+
+ /* view menu */
+ void viewAt50();
+ void viewAt100();
+ void viewAt150();
+ void viewAt200();
+
+ /* file menu */
+ void fileNew();
+ void open();
+ void openSession();
+ void openExample();
+ void save();
+ void saveAs();
+ void quit();
+
+ void open(QString filename);
+ bool save(QString filename);
+ void setModified(bool m = true);
+
+ void execute();
+ void endexecute();
+ void rename();
+ void retrieve();
+ void publish();
+
+ void addModule(const char *module);
+ void changePortPositions();
+
+ void oldFileNewWhatTheHellDoesItDo(int what);
+};
+
+#endif
diff --git a/arts/builder/menumaker.cpp b/arts/builder/menumaker.cpp
new file mode 100644
index 00000000..54e32e2b
--- /dev/null
+++ b/arts/builder/menumaker.cpp
@@ -0,0 +1,212 @@
+#include "menumaker.h"
+#include <stdio.h>
+#include <assert.h>
+#include <arts/debug.h>
+
+using namespace std;
+
+MenuEntry::MenuEntry(MenuMaker *menumaker, KActionMenu *parent, const char *text)
+ : menumaker(menumaker), text(text)
+{
+ action = new KAction(QString::fromLocal8Bit(text));
+ parent->insert(action);
+ connect(action, SIGNAL(activated()), this, SLOT(activated()));
+}
+
+void MenuEntry::activated()
+{
+ menumaker->menuActivated(text);
+}
+
+MenuCategory::MenuCategory(const QString& name, const char *prefix, KActionMenu *menu)
+{
+ _menu = menu;
+ _name = name;
+ _catchall = (strcmp(prefix,"*") == 0);
+ addPrefix(prefix);
+}
+
+QString MenuCategory::name()
+{
+ return _name;
+}
+
+bool MenuCategory::catchall()
+{
+ return _catchall;
+}
+
+void MenuCategory::addPrefix(const char *prefix)
+{
+ prefixList.push_back(prefix);
+}
+
+bool MenuCategory::matches(const char *item)
+{
+ string pattern = string(item)+"$";
+ size_t patternlen = strlen(pattern.c_str());
+
+ list<string>::iterator i;
+
+ for(i=prefixList.begin();i != prefixList.end(); ++i)
+ {
+ const char *prefix = (*i).c_str();
+
+ if(patternlen >= strlen(prefix))
+ {
+ if(strncmp(prefix,pattern.c_str(),strlen(prefix)) == 0) return true;
+ }
+ }
+ return false;
+}
+
+KActionMenu *MenuCategory::menu()
+{
+ return _menu;
+}
+
+MenuMaker::MenuMaker(KActionMenu *root)
+{
+ categories.push_back(new MenuCategory("","",root));
+}
+
+// Add more specific categories later, more general categories first.
+//
+// for instance use
+// addCategory("&Synthesis", "Synth_");
+// addCategory("&Synthesis/&Waveforms", "Synth_WAVE");
+
+void MenuMaker::addCategory(const QString& name, const char *prefix)
+{
+ MenuCategory *mc = 0,*pc = 0;
+
+ mc = lookupCategoryByName(name);
+ if(mc)
+ {
+ mc->addPrefix(prefix);
+ return; // already exists
+ }
+
+ pc = lookupCategoryByName(basename(name));
+ if(pc)
+ {
+ KActionMenu *newMenu = new KActionMenu(catname(name));
+ pc->menu()->insert(newMenu);
+ /* 000 */
+ /*connect(newMenu,SIGNAL(activated(int)),this,SLOT(menuactivated(int)));
+ pc->menu()->insertItem(catname(name).c_str(), newMenu, CAT_MAGIC_ID);*/
+ arts_debug("inserting a menu called '%s' in the parent menu '%s'",
+ catname(name).local8Bit().data(),pc->name().local8Bit().data());
+ categories.push_back(new MenuCategory(name,prefix,newMenu));
+ }
+ else
+ {
+ arts_debug("Parent category '%s' for '%s' is missing.",
+ basename(name).local8Bit().data(),name.local8Bit().data());
+ }
+}
+
+MenuCategory *MenuMaker::lookupCategoryByName(const QString& name)
+{
+ MenuCategory *mc = 0;
+ list<MenuCategory *>::iterator i;
+ for(i=categories.begin();i != categories.end();++i)
+ {
+ if((*i)->name() == name) mc = (*i);
+ }
+ return mc;
+}
+
+void MenuMaker::addItem(const char *name, int index)
+{
+ MenuCategory *mc = 0;
+
+ list<MenuCategory *>::iterator i;
+ for(i=categories.begin();i != categories.end();++i)
+ if((*i)->matches(name)) mc = (*i);
+ assert(mc); // root category should always match
+
+ if(mc->name().isEmpty())
+ {
+ // if we hit the root category, it may be better to move the thing
+ // into the catchall category (looks cleaner)
+ for(i=categories.begin();i != categories.end();++i)
+ if((*i)->catchall()) mc = (*i);
+ }
+ //mc->menu()->insertItem(name,index); 000
+ //mc->menu()->insert(new KAction(name)); // index??
+ new MenuEntry(this, mc->menu(), name);
+ /*
+ KAction *action = new KAction(QString(name));
+ mc->menu()->insert(action);
+ */
+ //action->plug(mc->menu());
+ //mc->menu()->insert(new KAction(name)); // index??
+}
+
+QString MenuMaker::basename(const QString& name)
+{
+ QString result = "";
+
+ int i = name.findRev('/');
+ if(i != -1)
+ result = name.left(i);
+
+ arts_debug("basename(%s) => %s",name.local8Bit().data(),
+ result.local8Bit().data());
+ return result;
+}
+
+QString MenuMaker::catname(const QString& name)
+{
+ int i = name.findRev('/');
+ if(i >= 0)
+ return name.mid(i+1);
+
+ return name;
+}
+
+void MenuMaker::clear()
+{
+ list<MenuCategory *>::iterator i;
+ for(i=categories.begin();i != categories.end();++i)
+ {
+ /* 000
+ KActionMenu *m = (*i)->menu();
+ unsigned int k;
+
+ k = 0;
+ while(k<m->count())
+ {
+ if(m->idAt(k) != CAT_MAGIC_ID)
+ {
+ m->removeItemAt(k);
+ k = 0;
+ }
+ else
+ {
+ k++;
+ }
+ }
+ */
+ }
+}
+
+const char *MenuMaker::findID(int id)
+{
+ /* 000 ?
+ list<MenuCategory *>::iterator i;
+ for(i=categories.begin();i != categories.end();i++)
+ {
+ const char *name = (*i)->menu()->text(id);
+ if(name) return(name);
+ } */
+ return 0;
+}
+
+void MenuMaker::menuActivated(const char *text)
+{
+ emit activated(text);
+}
+
+#include "menumaker.moc"
diff --git a/arts/builder/menumaker.h b/arts/builder/menumaker.h
new file mode 100644
index 00000000..5b999dc5
--- /dev/null
+++ b/arts/builder/menumaker.h
@@ -0,0 +1,70 @@
+#ifndef __MENUMAKER_H__
+#define __MENUMAKER_H__
+
+#include <kaction.h>
+#include <qobject.h>
+#include <string>
+#include <list>
+
+class MenuMaker;
+
+class MenuEntry : public QObject
+{
+ Q_OBJECT
+
+protected:
+ MenuMaker *menumaker;
+ KAction *action;
+ QCString text;
+
+public:
+ MenuEntry(MenuMaker *menumaker, KActionMenu *parent, const char *text);
+
+public slots:
+ void activated();
+};
+
+class MenuCategory
+{
+protected:
+ KActionMenu *_menu;
+ QString _name;
+ std::list<std::string> prefixList;
+ bool _catchall;
+
+public:
+ MenuCategory(const QString& name, const char *prefix, KActionMenu *menu);
+
+ void addPrefix(const char *prefix);
+ QString name();
+ KActionMenu *menu();
+
+ bool catchall();
+ bool matches(const char *item);
+};
+
+class MenuMaker :public QObject
+{
+ Q_OBJECT
+
+ std::list<MenuCategory *> categories;
+public:
+ enum { CAT_MAGIC_ID = 10000 };
+
+ MenuMaker(KActionMenu *root);
+
+ void addCategory(const QString& name, const char *prefix);
+ MenuCategory *lookupCategoryByName(const QString& name);
+ void addItem(const char *name, int i);
+ QString basename(const QString& name);
+ QString catname(const QString& name);
+
+ void clear();
+
+ const char *findID(int id);
+
+ void menuActivated(const char *text);
+signals:
+ void activated(const char *text);
+};
+#endif
diff --git a/arts/builder/module.cpp b/arts/builder/module.cpp
new file mode 100644
index 00000000..250ee3a2
--- /dev/null
+++ b/arts/builder/module.cpp
@@ -0,0 +1,439 @@
+ /*
+
+ Copyright (C) 1998-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 "module.h"
+#include "drawutils.h"
+#include <stdio.h>
+#include <arts/debug.h>
+
+#include <qpalette.h>
+#include <qdrawutil.h>
+#include <kiconloader.h>
+#include <algorithm>
+
+using namespace std;
+
+ModulePort::ModulePort(StructureComponent *owner, const string& description,
+ int drawsegment, Direction direction, Arts::PortDesc PortDesc)
+{
+ selected = false;
+
+ this->owner = owner; // whats the syntax for that again?
+ this->drawsegment = drawsegment;
+ this->direction = direction;
+ this->PortDesc = PortDesc;
+ this->description = description.c_str();
+
+ pdID = PortDesc.ID();
+
+ isinitarg = (PortDesc.type().connType == Arts::conn_property);
+ if(isinitarg) arts_debug("port %s is an init arg", (const char *)this->description.latin1());
+ arts_debug("port %s created", (const char *)this->description.latin1());
+ conntype = none;
+ route_owner = 0;
+}
+
+bool ModulePort::down()
+{
+ return (PortDesc.isConnected() || PortDesc.hasValue() || selected);
+}
+
+QColor ModulePort::color(bool isInterface)
+{
+ if(selected) return QColor(255, 165, 0);
+
+ if(PortDesc.hasValue())
+ {
+ if(isinitarg) return QColor(180, 180, 180);
+ return QColor(100, 100, 255);
+ }
+
+ if(isinitarg) return QColor(128, 128, 128);
+
+ if(isInterface) return QColor(100, 100, 100);
+ return QColor(43, 43, 168);
+}
+
+Module::Module(Arts::ModuleDesc module, Arts::StructureDesc structuredesc,
+ StructureCanvas *canvas) : StructureComponent(canvas)
+{
+ StructureDesc = structuredesc;
+ ModuleDesc = module;
+
+ _x = ModuleDesc.x();
+ _y = ModuleDesc.y();
+ initModule();
+}
+
+Module::Module(const Arts::ModuleInfo& minfo, Arts::StructureDesc structuredesc,
+ StructureCanvas *canvas) : StructureComponent(canvas)
+{
+ StructureDesc = structuredesc;
+ ModuleDesc = StructureDesc.createModuleDesc(minfo);
+
+ initModule();
+}
+
+void Module::initModule()
+{
+ QString iconname;
+ KIconLoader iconloader;
+
+ _selected = false;
+ _visible = false;
+ _height = 1;
+ _name = ModuleDesc.name().c_str();
+ _pixmap = NULL;
+
+// test if pixmap available
+
+ iconname = _name + ".xpm";
+
+ _pixmap = new QPixmap(iconloader.loadIcon(iconname, KIcon::User));
+ if(!_pixmap->height())
+ {
+ iconname = _name + ".png";
+ delete _pixmap;
+ _pixmap = new QPixmap( iconloader.loadIcon( iconname, KIcon::User ) );
+ if( !_pixmap->height() )
+ {
+ delete _pixmap;
+ _pixmap = 0;
+ }
+ }
+// try again without Arts:: - prefix
+
+ if(iconname.startsWith("Arts::"))
+ {
+ iconname = iconname.mid(6);
+
+ _pixmap = new QPixmap(iconloader.loadIcon(iconname, KIcon::User));
+ if(!_pixmap->height())
+ {
+ iconname.replace( iconname.length() - 4, 3, "png" );
+ delete _pixmap;
+ _pixmap = new QPixmap(iconloader.loadIcon(iconname, KIcon::User));
+ if( !_pixmap->height() )
+ {
+ delete _pixmap;
+ _pixmap = 0;
+ }
+ }
+ }
+/*
+ FILE *test = fopen(QFile::encodeName(iconname), "r");
+ if(test)
+ {
+ pixmap = new QPixmap(iconname);
+ fclose(test);
+ }
+*/
+
+// create lists with inports & outports for this module
+// and bind them to it ...
+
+ arts_debug("Getting ports...");
+ vector<Arts::PortDesc >*ports = ModuleDesc.ports();
+ unsigned long portpos;
+ long indraw = 1, outdraw = 2;
+
+ for(portpos = 0; portpos < ports->size(); portpos++)
+ {
+ Arts::PortDesc pd = (*ports)[portpos];
+ ModulePort *p;
+
+ arts_debug("CREATING %s", pd.name().c_str());
+ switch(pd.type().direction)
+ {
+ case Arts::input:
+ p = new ModulePort(this, pd.name(), indraw++,
+ ModulePort::in, pd);
+ inports.push_back(p);
+ break;
+ case Arts::output:
+ p = new ModulePort(this, pd.name(), outdraw++,
+ ModulePort::out, pd);
+ outports.push_back(p);
+ break;
+ default:
+ assert(false); // shouldn't happen!
+ }
+ }
+
+ delete ports;
+
+ _width = 1 + max(inports.size(), outports.size() + 1);
+
+ mdID = ModuleDesc.ID();
+ isInterface = ModuleDesc.isInterface();
+}
+
+Module::~Module()
+{
+ arts_debug("hide...");
+ hide();
+ arts_debug("sdfmd...");
+ list<ModulePort *>::iterator i;
+
+ for(i = inports.begin(); i != inports.end(); ++i) delete *i;
+ inports.clear();
+
+ for(i = outports.begin(); i != outports.end(); ++i) delete *i;
+ outports.clear();
+
+ StructureDesc.freeModuleDesc(ModuleDesc);
+ arts_debug("ok...");
+ delete _pixmap;
+}
+
+bool Module::moveInternal(int x, int y)
+{
+ return ModuleDesc.moveTo(x, y);
+}
+
+int Module::width() const
+{
+ return _width;
+}
+
+int Module::height() const
+{
+ return _height;
+}
+
+StructureComponent::ComponentType Module::type()
+{
+ return ctModule;
+}
+
+bool Module::drawNeedsBackground(int segment)
+{
+ return (segment == 0);
+}
+
+void Module::drawSegment(QPainter *p, int cellsize, int segment)
+{
+ int border = cellsize / 10; // for the logo
+ int ltop = (cellsize - border)/2;
+ int lbot = (cellsize + border)/2;
+
+ QColor mcolor(43, 43, 168);
+ QColor mcolorlight(164, 176, 242);
+
+ if(isInterface)
+ {
+ mcolor = QColor(100, 100, 100);
+ mcolorlight = QColor(160, 160, 160);
+ }
+ QColorGroup g( Qt::white, Qt::blue, mcolorlight, mcolor.dark(), mcolor,
+ Qt::black, Qt::black );
+ QBrush fill( mcolor );
+ QPen textpen(QColor(255, 255, 180), 1);
+
+ if(segment == 0)
+ {
+ qDrawShadePanel(p, border, border, cellsize - 2*border + 1, cellsize - 2*border + 1,
+ g, false, 1, &fill);
+ p->fillRect(cellsize - border - 1, ltop, cellsize, lbot - ltop + 1, fill);
+ p->setPen(g.light());
+ p->drawLine(cellsize - border, ltop - 1, cellsize, ltop - 1);
+ p->setPen(g.dark());
+ p->drawLine(cellsize - border, lbot + 1, cellsize, lbot + 1);
+ if(_pixmap)
+ {
+ int destsize = (cellsize - 4*border);
+ float sx = (float)destsize/(float)_pixmap->width();
+ float sy = (float)destsize/(float)_pixmap->height();
+
+ QWMatrix matrix;
+ matrix.scale(sx, sy);
+ QPixmap pmscaled = _pixmap->xForm(matrix);
+ p->drawPixmap(border*2, border*2, pmscaled);
+ }
+ return;
+ }
+
+ p->fillRect(0, 0, cellsize, cellsize, fill);
+
+ /*
+ * take care of the bevel lines around the module
+ */
+
+ p->setPen(g.light());
+ p->drawLine(0, 0, cellsize - 1, 0);
+ if(segment < 2)
+ p->drawLine(0, 0, 0, cellsize - 1);
+
+ p->setPen(g.dark());
+ p->drawLine(cellsize - 1, cellsize - 1, 0, cellsize - 1);
+ if(segment == 0 || segment == width() - 1)
+ p->drawLine(cellsize - 1, cellsize - 1, cellsize - 1, 0);
+
+ /*
+ * now draw the ports
+ */
+ int direction;
+
+ for(direction = 0;direction < 2; direction++)
+ {
+ ModulePort *port = findPort(segment, direction);
+
+ if(port)
+ {
+ int border = cellsize/7;
+ int textwidth;
+ QString label = DrawUtils::cropText(p, port->description,
+ cellsize/2, textwidth);
+
+ QBrush pbrush(port->color(isInterface));
+
+ port->clickrect = QRect(border, direction * cellsize/2 + border,
+ cellsize/2 - 2*border, cellsize/2 - 2*border);
+ qDrawShadePanel(p, port->clickrect, g, port->down(), 2, &pbrush);
+
+#if 0
+ QBrush fillport(fill);
+ if(port->isinitarg)
+ {
+ fillport = QColor(128, 128, 128);
+ }
+
+ if(port->selected)
+ {
+ QBrush fillorange(QColor(255, 165, 0));
+ qDrawShadePanel(p, port->clickrect, g, true, 2, &fillorange);
+ }
+ else
+ {
+ if(port->PortDesc->isConnected())
+ {
+ qDrawShadePanel(p, port->clickrect, g, true, 2, &fillport);
+ }
+ else if(port->PortDesc->hasValue())
+ {
+ QBrush fillp(QColor(100, 100, 255));
+ if(port->isinitarg)
+ {
+ fillp = QColor(180, 180, 180);
+ }
+ qDrawShadePanel(p, port->clickrect, g, true, 2, &fillp);
+ }
+ else // not connected and no value();
+ qDrawShadePanel(p, port->clickrect, g, false, 2, &fillport);
+ }
+#endif
+
+ p->setPen(textpen);
+ p->drawText((cellsize - border)/2,
+ (1 + direction) * (cellsize/2) - border, label);
+ }
+ }
+
+ /*
+ * if it was the rightmost part of the module, it has the module name
+ * and the connection to the logo as well
+ */
+
+ if(segment == 1)
+ {
+ // object type label
+ int textwidth;
+ QString label = DrawUtils::cropText(p, _name, cellsize - 4, textwidth);
+
+ p->setPen(textpen);
+ p->fillRect(1, cellsize - 16, textwidth + 7, 15, QBrush(g.dark()));
+ p->drawText(4, cellsize - 5, label);
+
+ // logo connection
+ p->setPen(mcolor);
+ p->drawLine(0, ltop, 0, lbot);
+ }
+
+ /*
+ * when selected, draw a line of white dots around the module
+ */
+
+ if(selected())
+ {
+ QPen pen(Qt::white, 1, Qt::DotLine);
+
+ p->setPen(pen);
+ p->drawLine(0, 0, cellsize - 1, 0);
+ p->drawLine(0, cellsize - 1, cellsize - 1, cellsize - 1);
+ if(segment == 1)
+ p->drawLine(0, 0, 0, cellsize - 1);
+ if(segment == _width - 1)
+ p->drawLine(cellsize - 1, 0, cellsize - 1, cellsize - 1);
+ }
+}
+
+ModulePort *Module::findPort(int xoffset, int direction)
+{
+ list<ModulePort *>*ports;
+ list<ModulePort *>::iterator i;
+
+ long n;
+
+ if(direction == 0) ports = &inports; else ports = &outports;
+
+ i = ports->begin();
+ n = xoffset - 1 - direction;
+
+ if(n < (long)ports->size() && n >= 0)
+ {
+ while(n > 0) { n--; i++; }
+ return (*i);
+ }
+ return(NULL);
+}
+
+ModulePort *Module::portAt(int segment, int x, int y)
+{
+ for(int direction = 0; direction < 2; direction++)
+ {
+ ModulePort *port = findPort(segment, direction);
+ if(port)
+ {
+ QPoint clickpoint(x, y);
+ if(port->clickrect.contains(clickpoint)) return port;
+ }
+ }
+ return 0;
+}
+
+void Module::dumpPorts(list<ModulePort *>& ports)
+{
+ list<ModulePort *>::iterator i;
+ for(i = inports.begin(); i != inports.end(); ++i) ports.push_back(*i);
+ for(i = outports.begin(); i != outports.end(); ++i) ports.push_back(*i);
+}
+
+QPixmap *Module::pixmap()
+{
+ return _pixmap;
+}
+
+QString Module::name()
+{
+ return _name;
+}
+
+// vim: sw=4 ts=4 noet
diff --git a/arts/builder/module.h b/arts/builder/module.h
new file mode 100644
index 00000000..ff19d44b
--- /dev/null
+++ b/arts/builder/module.h
@@ -0,0 +1,108 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef __MODULE_H_
+#define __MODULE_H_
+
+#include <list>
+
+#include <qpixmap.h>
+#include <qstring.h>
+#include <qrect.h>
+#include <ksimpleconfig.h>
+
+#include "artsbuilder.h"
+#include "scomponent.h"
+
+class ModulePort
+{
+ //ModulePort *connection;
+
+public:
+ Arts::PortDesc PortDesc;
+ long pdID;
+
+ enum ConnType {none, source, dest, value, conf};
+ enum Direction {in, out};
+
+ bool selected;
+ StructureComponent *owner;
+
+ QString description;
+ QRect clickrect;
+ ConnType conntype;
+ Direction direction;
+ int drawsegment;
+ bool isinitarg;
+
+ long route_owner;
+
+ ModulePort( StructureComponent *owner, const std::string& description,
+ int drawsegment, Direction direction, Arts::PortDesc PortDesc);
+
+ bool down();
+ QColor color(bool isInterface);
+};
+
+class Module :public StructureComponent
+{
+protected:
+ Arts::StructureDesc StructureDesc;
+ Arts::ModuleDesc ModuleDesc;
+
+ QPixmap *_pixmap;
+ QString _name;
+
+ int _width, _height;
+ bool moveInternal(int x, int y);
+
+ void initModule();
+
+public:
+ Module( Arts::ModuleDesc moduledesc, Arts::StructureDesc structuredesc,
+ StructureCanvas *canvas);
+ Module( const Arts::ModuleInfo& minfo, Arts::StructureDesc structuredesc,
+ StructureCanvas *canvas);
+ virtual ~Module();
+
+ ModulePort *findPort(int xoffset, int direction);
+
+ bool isInterface;
+
+ long mdID;
+ std::list<ModulePort *> inports, outports;
+
+// StructureComponent interface
+
+ int width() const;
+ int height() const;
+ ComponentType type();
+
+ ModulePort *portAt(int segment, int x, int y);
+ void dumpPorts(std::list<ModulePort *>& ports);
+
+ bool drawNeedsBackground(int segment);
+ void drawSegment(QPainter *dest, int cellsize, int segment);
+ QPixmap *pixmap();
+ QString name();
+ };
+
+#endif
diff --git a/arts/builder/mwidget.cpp b/arts/builder/mwidget.cpp
new file mode 100644
index 00000000..b6c3d841
--- /dev/null
+++ b/arts/builder/mwidget.cpp
@@ -0,0 +1,652 @@
+#include "mwidget.h"
+#include "autorouter.h"
+
+#include <arts/debug.h>
+
+//#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <qtimer.h>
+#include <qpainter.h>
+#include <qevent.h>
+
+#include "createtool.h"
+
+Structure *ModuleWidget::theStructure()
+{
+ return structure;
+}
+
+void ModuleWidget::addInterface ( const Arts::ModuleInfo& minfo )
+{
+ delete activeTool;
+ activeTool = new CreateInterfaceTool(this, minfo);
+}
+
+void ModuleWidget::addModule ( const Arts::ModuleInfo& minfo )
+{
+ delete activeTool;
+ activeTool = new CreateModuleTool(this, minfo);
+}
+
+void ModuleWidget::addPort ( const Arts::PortType& type )
+{
+ delete activeTool;
+ activeTool = new CreatePortTool(this, type);
+}
+
+StructurePort *ModuleWidget::insertPort( const Arts::PortType& type, int x, int y )
+{
+ StructurePort *port = structure->createStructurePort(type);
+ unselectAll();
+ port->move(x, y);
+ port->setSelected(true);
+ port->show();
+
+ return port;
+}
+
+void ModuleWidget::leaveTool(MWidgetTool *tool, bool wasModified)
+{
+ assert(tool == activeTool);
+ delete tool;
+ activeTool = 0;
+ if(wasModified)
+ emit modified(wasModified);
+}
+
+QPoint ModuleWidget::componentPos(const StructureComponent *component) const
+{
+ int cellx = 0, celly = 0;
+ colXPos(component->x(), &cellx);
+ rowYPos(component->y(), &celly);
+
+ return QPoint(cellx, celly);
+}
+
+QPoint ModuleWidget::portPos(const ModulePort *port) const
+{
+ int cellx = 0, celly = 0;
+ colXPos(port->owner->x() + port->drawsegment, &cellx);
+ rowYPos(port->owner->y(), &celly);
+
+ return QPoint(cellx, celly);
+}
+
+bool ModuleWidget::insertModule( Module *newModule )
+{
+ if(hasSpace(newModule, newModule->x(), newModule->y(), true))
+ {
+ newModule->show();
+ reRoute();
+ return true;
+ }
+ return false;
+}
+
+void ModuleWidget::findAt(int windowX, int windowY,
+ StructureComponent *&component, ModulePort *&port)
+{
+ int x = findCol(windowX);
+ int y = findRow(windowY);
+
+ component = structure->componentAt(x, y, false);
+
+ if(component)
+ {
+ int cellx = 0, celly = 0;
+ colXPos(x, &cellx);
+ rowYPos(y, &celly);
+
+ port = component->portAt(x - (component->x()),
+ windowX - cellx, windowY - celly);
+ }
+ else
+ port = 0L;
+}
+
+void ModuleWidget::selectComponent( StructureComponent *component, bool onlyThis )
+{
+ beginUpdate();
+ if(onlyThis)
+ unselectAll();
+
+ if(!(component->selected()))
+ {
+ component->setSelected(true);
+ emit componentSelected(component);
+ } else
+ if(!onlyThis)
+ {
+ component->setSelected(false);
+ emit componentSelected(0L);
+ }
+ endUpdate();
+}
+
+void ModuleWidget::mousePressEvent( QMouseEvent *e )
+{
+ if(activeTool)
+ {
+ activeTool->mousePressEvent(e);
+ return;
+ }
+
+ if( e->button() == LeftButton )
+ {
+ StructureComponent *component;
+ ModulePort *port;
+ findAt(e->x(), e->y(), component, port);
+
+ if(component)
+ {
+ if(port)
+ {
+ // user clicked in port
+ selectPort(port);
+
+ delete activeTool;
+ activeTool = new ConnectPortsTool(this, port);
+ }
+ else
+ {
+ // user clicked in component
+ activeTool = new MoveComponentsTool(this, e);
+
+ // maintain selected group when pressing the shift or control button
+ selectComponent(component, !((e->state() & ControlButton)
+ || (e->state() & ShiftButton)));
+ }
+ }
+ else
+ {
+ // unselect all if user clicks on background (without shift)
+ if(!(e->state() & ShiftButton))
+ {
+ beginUpdate();
+ unselectAll();
+ endUpdate();
+ }
+ }
+ }
+}
+
+void ModuleWidget::mouseMoveEvent( QMouseEvent *e )
+{
+ if(activeTool)
+ {
+ activeTool->mouseMoveEvent(e);
+ return;
+ }
+}
+
+void ModuleWidget::mouseReleaseEvent( QMouseEvent *e )
+{
+ if(activeTool)
+ {
+ activeTool->mouseReleaseEvent(e);
+ return;
+ }
+}
+
+// may be called with port == 0
+void ModuleWidget::selectPort( ModulePort *port, bool newMode )
+{
+ beginUpdate();
+
+ if(selectedPort && (selectedPort!= port))
+ {
+ // unselect previous
+ selectedPort->selected = false;
+ selectedPort->owner->redraw();
+ if(selectedPort->owner->selected())
+ emit componentSelected(selectedPort->owner);
+ else
+ emit portSelected(0L);
+ selectedPort = 0L;
+ }
+
+ if(port)
+ {
+ port->selected = newMode;
+ selectedPort = port;
+ selectComponent(selectedPort->owner);
+ selectedPort->owner->redraw();
+ }
+ emit portSelected(port); // FIXME: should be "portSelectionChanged"
+
+ endUpdate();
+}
+
+void ModuleWidget::startConnection( ModulePort *port )
+{
+ delete activeTool;
+ activeTool = new ConnectPortsTool(this, port);
+}
+
+void ModuleWidget::portPropertiesChanged( ModulePort *port )
+{
+ reRoute();
+}
+
+bool ModuleWidget::hasSpace(StructureComponent *c, int destx, int desty,
+ bool ignore_selected)
+{
+ if((destx < 0) || (desty < 0))
+ return false;
+ if((destx + c->width() > numCols()) || (desty + c->height() > numRows()))
+ return false;
+
+ for(int ddx = 0; ddx < c->width(); ddx++)
+ {
+ for(int ddy = 0; ddy < c->height(); ddy++)
+ {
+ if(structure->componentAt(destx + ddx, desty + ddy, ignore_selected))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ModuleWidget::paintCellBackground(QPainter *p, int y, int x)
+{
+ QColor bgcolor;
+
+ if((y & 1) == 1)
+ bgcolor = QColor(168, 168, 168);
+ else
+ bgcolor = QColor(146, 168, 146);
+
+ p->fillRect(0, 0, cellsize, cellsize, QBrush(bgcolor));
+
+ p->setPen(bgcolor.dark(115));
+ p->drawLine(0, 0, 0, cellsize - 1);
+ p->drawLine(0, 0, cellsize - 1, 0);
+
+ if(x == (numCols() - 1))
+ p->drawLine(cellsize - 1, 0, cellsize - 1, cellsize - 1);
+ if(y == (numRows() - 1))
+ p->drawLine(0, cellsize - 1, cellsize - 1, cellsize - 1);
+}
+
+void ModuleWidget::unselectAll()
+{
+ setSelectAll(false);
+}
+
+void ModuleWidget::setSelectAll(bool newstate)
+{
+ std::list<StructureComponent *>::iterator module;
+
+ for(module = structure->getComponentList()->begin();
+ module != structure->getComponentList()->end(); module++)
+ {
+ (*module)->setSelected(newstate);
+ }
+}
+
+void ModuleWidget::beginUpdate()
+{
+ updateDepth++;
+}
+
+void ModuleWidget::endUpdate()
+{
+ if(!--updateDepth)
+ {
+ std::list<QRect>::iterator i;
+
+ for(i = UpdateList.begin(); i != UpdateList.end(); i++)
+ {
+ redrawCells(*i);
+ }
+
+ UpdateList.clear();
+ }
+}
+
+void ModuleWidget::redrawRect(int x, int y, int width, int height)
+{
+ QRect r = QRect(x, y, width, height);
+
+ if(!updateDepth)
+ {
+ redrawCells(r);
+ }
+ else
+ {
+ UpdateList.push_back(r);
+ }
+}
+
+void ModuleWidget::redrawCells(QRect &r)
+{
+ int x, y;
+
+ for(x = r.left(); x <= r.right(); x++)
+ {
+ for(y = r.top(); y <= r.bottom(); y++)
+ {
+ updateCell(y, x, false);
+ }
+ }
+}
+
+
+void ModuleWidget::reRoute()
+{
+// clear everything
+ autorouter->clear();
+
+// add structure components (external ports/modules) to the router, so that
+// cables won't be drawn over them
+
+ std::list<StructureComponent *>::iterator c;
+ std::list<ModulePort *> portlist;
+
+ for(c = structure->getComponentList()->begin();
+ c != structure->getComponentList()->end(); c++)
+ {
+ StructureComponent *sc = *c;
+ autorouter->set(sc->x()*2, sc->y()*2,
+ (sc->x() + sc->width())*2 - 1,
+ (sc->y() + sc->height())*2 - 1, AutoRouter::solid);
+
+ sc->dumpPorts(portlist);
+ }
+
+ std::list<ModulePort *>::iterator pi;
+
+// build a map with all input ports to find corresponding ports of connections
+
+ std::map<long, ModulePort *> portmap;
+
+ for(pi = portlist.begin(); pi != portlist.end(); ++pi)
+ {
+ ModulePort *port = *pi;
+
+ if(port->direction == ModulePort::in) portmap[port->pdID] = port;
+ }
+
+// add connections to the router
+
+ /*
+ * assign colors after the following algorithm:
+ *
+ * - initialize assuming that each port has its own color
+ * - if two ports are connected, they must have the same color, that
+ * is, all references to the two colors must be made the same
+ *
+ * these colors are not used for drawing, but for making lines of
+ * different groups of ports not collide in the autorouter (ownership)
+ */
+ std::map<ModulePort *, long> color;
+ vector<long> owner(portlist.size());
+
+ long maxcolor = 0;
+ for(pi = portlist.begin(); pi != portlist.end(); ++pi)
+ color[*pi] = maxcolor++;
+
+ for(pi = portlist.begin(); pi != portlist.end(); ++pi)
+ {
+ ModulePort *src = *pi;
+ unsigned long c;
+ if(src->direction == ModulePort::out && src->PortDesc.isConnected())
+ {
+ vector<Arts::PortDesc> *conn = src->PortDesc.connections();
+
+ for(c = 0; c < conn->size(); c++)
+ {
+ ModulePort *dest = portmap[(*conn)[c].ID()];
+ long color_src = color[src];
+ long color_dest = color[dest];
+
+ if(color_src != color_dest)
+ {
+ std::list<ModulePort *>::iterator pi2;
+
+ for(pi2 = portlist.begin(); pi2 != portlist.end(); pi2++)
+ {
+ ModulePort *p = *pi2;
+
+ if(color[p] == color_dest) color[p] = color_src;
+ }
+ }
+ }
+ }
+ }
+
+ for(pi = portlist.begin(); pi != portlist.end(); ++pi)
+ {
+ ModulePort *p = *pi;
+
+ if(p->direction == ModulePort::out && p->PortDesc.isConnected())
+ {
+ ModulePort *src = p, *dest;
+ long& route_owner = owner[color[src]];
+ unsigned long c;
+
+ vector<Arts::PortDesc> *conn = p->PortDesc.connections();
+
+ for(c = 0; c < conn->size(); c++)
+ {
+ dest = portmap[(*conn)[c].ID()];
+ if(dest) // otherwise something bad has happend?
+ {
+/*
+ arts_debug("autoroute add connection port %s.%s to %s.%s",
+ src->owner->type.local8Bit().data(),src->description.local8Bit().data(),
+ dest->owner->type.local8Bit().data(),dest->description.local8Bit().data());
+*/
+
+ int x1 = (src->owner->x() + src->drawsegment)*2;
+ int y1 = src->owner->y()*2 + 1;
+
+ int x2 = (dest->owner->x() + dest->drawsegment)*2;
+ int y2 = dest->owner->y()*2;
+
+ route_owner = autorouter->connect(x1, y1, x2, y2, route_owner);
+ }
+ }
+
+ delete conn;
+ }
+ }
+
+ autorouter->sync();
+}
+
+void ModuleWidget::redrawAll()
+{
+// redraw everything
+ QRect updaterect(0, 0, cols, rows);
+ redrawCells(updaterect);
+}
+
+void ModuleWidget::paintConnection(QPainter *p, int x, int y, int arx, int ary)
+{
+ long linetype = autorouter->get(arx, ary);
+ long ud_owner = -1, lr_owner = -1, lr_break = 0, ud_break = 0;
+
+ autorouter->getowners(arx, ary, ud_owner, lr_owner);
+
+ p->setPen(QColor(255, 255, 255));
+
+/*
+ if(linetype == AutoRouter::none)
+ {
+ p->drawPoint(x + cellsize/4, y + cellsize/4);
+ }
+ if(linetype & AutoRouter::solid)
+ {
+ QBrush whitefill(QColor(255, 255, 255));
+
+ p->fillRect(x + cellsize/6, y + cellsize/6, cellsize/6, cellsize/6, whitefill);
+ }
+*/
+ x += cellsize/4;
+ y += cellsize/4;
+
+ // both used?
+ if(ud_owner != -1 && lr_owner != -1)
+ {
+ // and not of the same owner?
+ if(ud_owner != lr_owner)
+ {
+ // then we'll have to paint one of them broken
+ if(ud_owner > lr_owner)
+ lr_break = cellsize/8;
+ else
+ ud_break = cellsize/8;
+ }
+ }
+
+ if(linetype & AutoRouter::left)
+ p->drawLine(x - cellsize/4, y, x - lr_break, y);
+ if(linetype & AutoRouter::right)
+ p->drawLine(x + cellsize/4, y, x + lr_break, y);
+ if(linetype & AutoRouter::up)
+ p->drawLine(x, y - cellsize/4, x, y - ud_break);
+ if(linetype & AutoRouter::down)
+ p->drawLine(x, y + cellsize/4, x, y + ud_break);
+}
+
+void ModuleWidget::paintConnections(QPainter *p, int y, int x)
+{
+ // paints connections in the given 2x2-autorouter-block being a 1x1 block to the user
+ for(int dx = 0; dx < 2; dx++)
+ for(int dy = 0; dy < 2; dy++)
+ paintConnection(p, (cellsize*dx)/2, (cellsize*dy)/2, x*2 + dx, y*2 + dy);
+}
+
+void ModuleWidget::paintCell(QPainter *p, int y, int x)
+{
+#if 0 /* PORT */
+ if(theArtsBuilderApp->eventStackDepth() > 1)
+ {
+ // FIXME: set some redraw flag or something like that
+ return;
+ }
+#endif
+
+ std::list<StructureComponent *>::iterator c;
+ for(c = structure->getComponentList()->begin();
+ c != structure->getComponentList()->end(); c++)
+ {
+ StructureComponent *mwc = *c;
+ if(y == mwc->y() && mwc->visible())
+ {
+ int xoffset = x - mwc->x();
+
+ if(xoffset >= 0 && xoffset < mwc->width())
+ {
+ if(mwc->drawNeedsBackground(xoffset))
+ paintCellBackground(p, y, x);
+
+ mwc->drawSegment(p, cellsize, xoffset);
+ paintConnections(p, y, x);
+ return;
+ }
+ }
+ }
+ paintCellBackground(p, y, x);
+ paintConnections(p, y, x);
+}
+
+// ---------------------------------------------------------------------------
+// public part of modulewidget
+// ---------------------------------------------------------------------------
+
+void ModuleWidget::setZoom(int zoom)
+{
+ cellsize = (int)(50.0 * (float)zoom/100);
+
+ setCellHeight(cellsize);
+ setCellWidth(cellsize);
+ updateTableSize();
+ resize(cellsize*cols, cellsize*rows);
+}
+
+void ModuleWidget::selectAll()
+{
+ setSelectAll(true);
+}
+
+void ModuleWidget::reInit()
+{
+ emit componentSelected(0);
+ selectedPort = 0L;
+
+ delete activeTool;
+ activeTool = 0L;
+
+ reRoute();
+}
+
+void ModuleWidget::delModule()
+{
+ int numSelected = structure->countSelected();
+
+ if(!numSelected) return;
+
+ if(KMessageBox::warningContinueCancel(0,
+ i18n("Delete %n selected module, port or connection? (No undo possible.)",
+ "Delete %n selected modules, ports and connections? (No undo possible.)",
+ numSelected), QString::null, i18n("&Delete")) == KMessageBox::Continue)
+ {
+ selectPort(0L);
+ emit componentSelected(0);
+ structure->deleteSelected();
+ reRoute();
+ }
+}
+
+void ModuleWidget::autoRedrawRouter()
+{
+ if(autorouter->needRedraw()) redrawAll();
+}
+
+ModuleWidget::ModuleWidget(Structure *structure, QWidget *parent, const char *name, WFlags f)
+ : QtTableView( parent, name, f),
+ updateDepth( 0 ),
+ activeTool( 0L ),
+ structure( structure ),
+ selectedPort( 0L )
+{
+ arts_debug("PORT: mw; getmodulelist");
+ this->ModuleList = structure->getModuleList();
+ arts_debug("PORT: mw; cols&rows");
+
+ cols = 24;
+ rows = 32;
+
+ setNumCols(cols);
+ setNumRows(rows);
+ setTableFlags(Tbl_autoScrollBars);
+ setZoom(100);
+
+ setFocusPolicy( NoFocus );
+
+ arts_debug("PORT: mw; bgmode");
+ setBackgroundMode(NoBackground);
+
+ arts_debug("PORT: mw; new ar %d,%d", cols, rows);
+ autorouter = new AutoRouter(cols*2, rows*2);
+
+ arts_debug("PORT: mw; new ar ok - qtimer");
+ QTimer *timer = new QTimer( this );
+ connect( timer, SIGNAL(timeout()),
+ this, SLOT(autoRedrawRouter()) );
+
+ arts_debug("PORT: mw; tstart");
+ timer->start( 100, FALSE ); // 100 ms reoccurring check
+}
+
+ModuleWidget::~ModuleWidget()
+{
+ delete autorouter;
+}
+
+#include "mwidget.moc"
diff --git a/arts/builder/mwidget.h b/arts/builder/mwidget.h
new file mode 100644
index 00000000..e6716e3e
--- /dev/null
+++ b/arts/builder/mwidget.h
@@ -0,0 +1,129 @@
+ /*
+
+ Copyright (C) 1999 Stefan Westerfeld <stefan@space.twc.de>,
+ Hans Meine <hans_meine@gmx.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ */
+
+#ifndef MWIDGET_H
+#define MWIDGET_H
+
+#include "structure.h"
+#include "module.h"
+#include "scomponent.h"
+
+#include "qttableview.h"
+
+class AutoRouter;
+class MWidgetTool;
+
+class ModuleWidget :public QtTableView, public StructureCanvas
+{
+ Q_OBJECT
+ friend class MWidgetTool;
+ friend class CreateTool;
+ friend class CreateInterfaceTool;
+ friend class CreateModuleTool;
+ friend class CreatePortTool;
+ friend class MoveComponentsTool;
+ friend class ConnectPortsTool;
+
+protected:
+ int cellsize, cols, rows;
+ int updateDepth;
+
+ MWidgetTool *activeTool;
+ AutoRouter *autorouter;
+ Structure *structure;
+
+// for connecting ports
+
+ ModulePort *selectedPort;
+
+ std::list<Module *> *ModuleList;
+ std::list<QRect> UpdateList;
+
+ void paintCell(QPainter *p, int y, int x);
+ void paintCellBackground(QPainter *p, int y, int x);
+ void paintConnection(QPainter *p, int x, int y, int arx, int ary);
+ void paintConnections(QPainter *p, int y, int x);
+ void mousePressEvent( QMouseEvent *e );
+ void mouseMoveEvent( QMouseEvent *e );
+ void mouseReleaseEvent( QMouseEvent *e );
+
+ bool hasSpace(StructureComponent *c, int destx, int desty,
+ bool ignore_selected = false);
+
+ void reRoute();
+ void setSelectAll(bool newstate);
+
+ void beginUpdate();
+ void redrawCells(QRect &r);
+ void redrawAll();
+ void endUpdate();
+
+// for StructureComponents:
+
+ void redrawRect(int x, int y, int width, int height);
+
+// for CreateTool:
+
+ bool insertModule(Module *newModule);
+ StructurePort *insertPort(const Arts::PortType& type, int x, int y);
+
+// for this and ConnectTool:
+
+ void findAt(int windowX, int windowY,
+ StructureComponent *&component,
+ ModulePort *&port);
+
+signals:
+ void portSelected( ModulePort * );
+ void componentSelected( StructureComponent * );
+ void modified(bool); // the bool mod. flag is always true for easier connects
+
+public:
+ Structure *theStructure();
+
+ void addModule(const Arts::ModuleInfo& minfo);
+ void addInterface(const Arts::ModuleInfo& minfo);
+ void addPort(const Arts::PortType& type);
+ void reInit();
+ void leaveTool(MWidgetTool *tool, bool wasModified= false);
+
+ QPoint componentPos(const StructureComponent *component) const;
+ QPoint portPos(const ModulePort *port) const;
+
+ ModuleWidget( Structure *structure, QWidget *parent = 0,
+ const char *name = 0, WFlags f = 0);
+
+ ~ModuleWidget();
+
+public slots:
+ void autoRedrawRouter();
+ void setZoom(int zoom);
+ void delModule();
+ void selectAll();
+ void unselectAll();
+
+ void selectPort( ModulePort *port, bool newMode = true );
+ void selectComponent( StructureComponent *component, bool onlyThis = true );
+ void startConnection( ModulePort * );
+ void portPropertiesChanged( ModulePort *port );
+};
+
+#endif // MWIDGET_H
diff --git a/arts/builder/pics/Makefile.am b/arts/builder/pics/Makefile.am
new file mode 100644
index 00000000..26e29f8f
--- /dev/null
+++ b/arts/builder/pics/Makefile.am
@@ -0,0 +1,24 @@
+# this 10 paths are KDE specific. Use them:
+# kde_htmldir Where your docs should go to. (contains lang subdirs)
+# kde_appsdir Where your application file (.kdelnk) should go to.
+# kde_icondir Where your icon should go to.
+# kde_minidir Where your mini icon should go to.
+# kde_datadir Where you install application data. (Use a subdir)
+# kde_locale Where translation files should go to.(contains lang subdirs)
+# kde_cgidir Where cgi-bin executables should go to.
+# kde_confdir Where config files should go to.
+# kde_mimedir Where mimetypes should go to.
+# kde_toolbardir Where general toolbar icons should go to.
+# kde_wallpaperdir Where general wallpapers should go to.
+
+pix_DATA = Synth_ADD.xpm Synth_ATAN_SATURATE.xpm Synth_BUS_DOWNLINK.xpm \
+ Synth_BUS_UPLINK.xpm Synth_DEBUG.xpm Synth_ENVELOPE_ADSR.xpm \
+ Synth_FILEPLAY.xpm Synth_MIDI_DEBUG.xpm Synth_MUL.xpm Synth_PLAY.xpm \
+ Synth_PLAY_WAV.xpm Synth_PSCALE.xpm Synth_SEQUENCE.xpm Synth_WAVE_SAW.xpm \
+ Synth_WAVE_SIN.xpm Synth_WAVE_SQUARE.xpm Synth_WAVE_TRI.xpm Synth_XFADE.xpm \
+ Synth_MOOG_VCF.xpm Synth_RC.xpm Synth_SHELVE_CUTOFF.xpm Synth_MULTI_ADD.xpm \
+ Synth_AMAN_PLAY.xpm Synth_SEQUENCE_FREQ.png Synth_DIV.xpm
+
+pixdir = $(kde_datadir)/artsbuilder/pics/
+
+KDE_ICON = artsbuilder action-artsbuilderexecute
diff --git a/arts/builder/pics/Synth_ADD.xpm b/arts/builder/pics/Synth_ADD.xpm
new file mode 100644
index 00000000..d3ff5f82
--- /dev/null
+++ b/arts/builder/pics/Synth_ADD.xpm
@@ -0,0 +1,305 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 234 2",
+/* colors */
+" c #535B83",
+" . c #34427F",
+" X c #DBDDE4",
+" o c #303C7B",
+" O c #2E3A79",
+" + c #4A517A",
+" @ c #2C3877",
+" # c #4D589E",
+" $ c #2C356D",
+" % c #354283",
+" & c #B8BAC8",
+" * c #334081",
+" = c #1E2869",
+" - c #283476",
+" ; c #3F4A7C",
+" : c #475591",
+" > c #37437E",
+" , c #232E71",
+" < c #202A6E",
+" 1 c #43518D",
+" 2 c #1F2A6D",
+" 3 c #1E286C",
+" 4 c #1D286B",
+" 5 c #2B367C",
+" 6 c #46517C",
+" 7 c #4D5D9A",
+" 8 c #1A235E",
+" 9 c #394783",
+" 0 c #485795",
+" q c #27316E",
+" w c #465593",
+" e c #525A81",
+" r c #515A80",
+" t c #34417E",
+" y c #323F7C",
+" u c #212B68",
+" i c #606BB3",
+" p c #2E3978",
+" a c #252F6F",
+" s c #344181",
+" d c #323F7F",
+" f c #303D7D",
+" g c #2F3B7C",
+" h c #2D397A",
+" j c #3D498D",
+" k c #293576",
+" l c #283375",
+" z c #232D70",
+" x c #202B6D",
+" c c #53649F",
+" v c #1E296B",
+" b c #B2B5C4",
+" n c #1D276A",
+" m c #2D377D",
+" M c #2B377B",
+" N c #4E5E9A",
+" B c #2A357A",
+" V c #293379",
+" C c #283378",
+" Z c #979AB0",
+" A c #4B5A97",
+" S c #495895",
+" D c #485894",
+" F c #475693",
+" G c #455491",
+" H c #43528F",
+" J c #33407C",
+" K c #C5C8D3",
+" L c #30396F",
+" P c #3F4B81",
+" I c #717591",
+" U c #313E7D",
+" Y c #202A69",
+" T c #D7D9E1",
+" R c #D6D7E0",
+" E c #2C3878",
+" W c #273273",
+" Q c #48529A",
+" ! c #253071",
+" ~ c #6A6F8D",
+" ^ c #232E6F",
+" / c #3A4475",
+" ( c #434E95",
+" ) c #B6B8C7",
+" _ c #35417A",
+" ` c #212C6D",
+" ' c #202A6C",
+" ] c #232D65",
+" [ c #1F2A6B",
+" { c #374072",
+" } c #2C387B",
+" | c #1C2668",
+". c #9A9DB2",
+".. c #3B468D",
+".X c #29336E",
+".o c #384580",
+".O c #232E72",
+".+ c #465591",
+".@ c #333E85",
+".# c #212C70",
+".$ c #384276",
+".% c #202A6F",
+".& c #323F7A",
+".* c #2F3A81",
+".= c #1E286D",
+".- c #777C96",
+".; c #404F8B",
+".: c #3E4D89",
+".> c #3D4B88",
+"., c #A9ACBD",
+".< c #6671BA",
+".1 c #313D7C",
+".2 c #4D547D",
+".3 c #D9DAE2",
+".4 c #2F3B7A",
+".5 c #D6D8DF",
+".6 c #2D3978",
+".7 c #D5D6DE",
+".8 c #2C3777",
+".9 c #2B3776",
+".0 c #2B3576",
+".q c #283373",
+".w c None",
+".e c #242F6F",
+".r c #444F95",
+".t c #222D6D",
+".y c #EEEFF3",
+".u c #B4B7C4",
+".i c #404B91",
+".p c #1D2768",
+".a c #2B3779",
+".s c #3C478D",
+".d c #333B6D",
+".f c #2A3578",
+".g c #293577",
+".h c #7E839C",
+".j c #36427D",
+".k c #333D84",
+".l c #303B81",
+".z c #1F296D",
+".x c #42508C",
+".c c #1E296C",
+".v c #51629E",
+".b c #2E397F",
+".n c #51609E",
+".m c #1D276B",
+".M c #404E8A",
+".N c #2A357B",
+".B c #4C5C99",
+".V c #29337A",
+".C c #4A5A97",
+".Z c #364280",
+".A c #9094AA",
+".S c #303C7A",
+".D c #1D2664",
+".F c #5D68B0",
+".G c #293473",
+".H c #273271",
+".J c #5762AA",
+".K c #334080",
+".L c #323E7F",
+".P c #45538B",
+".I c #303C7D",
+".U c #2B3678",
+".Y c #1B2465",
+".T c #2A3677",
+".R c #3C4982",
+".E c #273274",
+".W c #384288",
+".Q c #263273",
+".! c #263073",
+".~ c #253072",
+".^ c #171F57",
+"./ c #222C6F",
+".( c #B5B8C7",
+".) c #313C81",
+"._ c #1E286B",
+".` c #2D387D",
+".' c #343E70",
+".] c #1C2669",
+".[ c #4F5F9B",
+".{ c #2C367C",
+".} c #293479",
+".| c #2C3772",
+"X c #979BB0",
+"X. c #4B5B97",
+"XX c #273277",
+"Xo c #4A5996",
+"XO c #9499AD",
+"X+ c #253075",
+"X@ c #475793",
+"X# c #222C72",
+"X$ c #445390",
+"X% c #1F2A6F",
+"X& c #42518E",
+"X* c #787E98",
+"X= c #727692",
+"X- c #2B3574",
+"X; c #555FA7",
+"X: c #232D6C",
+"X> c #2F3B7B",
+"X, c #515BA3",
+"X< c #4B527C",
+"X1 c #293575",
+"X2 c #3A4589",
+"X3 c #4A559C",
+"X4 c #263172",
+"X5 c #465198",
+"X6 c #B7B9C8",
+"X7 c #424D94",
+"X8 c #1F296B",
+"X9 c #2D397C",
+"X0 c #1D2769",
+"Xq c #2A3579",
+"Xw c #454E79",
+"Xe c #3B4883",
+"Xr c #273376",
+"Xt c #38438A",
+"Xy c #273176",
+"Xu c #364188",
+"Xi c #9498AC",
+"Xp c #3C477A",
+"Xa c #242F73",
+"Xs c #475692",
+"Xd c #343F86",
+"Xf c #36427E",
+"Xg c #323D84",
+"Xh c #212B70",
+"Xj c #44528F",
+"Xk c #43528E",
+"Xl c #1F296E",
+"Xz c #323E7A",
+"Xx c #1E296D",
+"Xc c #41508C",
+/* pixels */
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.!XX C V CXyX+XaX# < v.p.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.|.1.WXuXg.* m 5.VXXX+X+.OX#.#Xh.%.z 8 8.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.>.r.i.sXtXuXg.* m 5.VXXX+X+.OX#.#Xh.%X%XlXl._ 8.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w > # # Q.r.i.sXtXdXg.* m.N CXXX+Xa.OX#.#Xh.%X%XlXx.=.= 3.] 8.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.wX;.JX, # Q (.i..XtXdXg.b m.N CXXX+Xa.OX#XhXh.%XlXlXx.= 3 3 3.m |.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w A i.FX;X, # Q (.i...WXdXg.b 5.}Xy.! , ,X#XhXhXh.%XlXlXx.= 3 3 4.m.m.] 8.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.<.<.F.JX;X,X3X5X7 j..Xu.@.).` 5 C.! ! a z.#XhXh.%.%XlXlXx.= 3 3.m.m.m n n |.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.P.<.< i.F.JX; #X3X5.i jXtXu.k.l m.f.|.' {Xp $ u '.%XlX%Xl.z.= 3 3 3.m.m n n n n |.^.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.wXo.<.<.< i.JX;X, # Q (.i.sXtXuXg.* }.0 { ~.hXw q u <XlXlXlXx.= 3 3 4.m.m n n nX0.] |.^.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w A.<.<.< i.F.JX;X,X3X5X7.i...WXdXg.b.U.0 ;.-.A., $ u 2.zXlXlXx.= 3 3 4.m.m n n nX0.].] |.^.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.wXo.<.<.< i.F.JX;X, # Q.r.i.sXtXu.k.l.b.U.0X<XO b.7 ~.d ] '.zXl.zXx 3 3 4.m.m n n nX0.].].] |.Y.^.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.P.<.<.< i.F.J.JX, #X3X5X7.i...WXdXg.*.`.f.0.2X .u.7 I.d ].z.cXl.z.= 3 3 3._.m.m n n nX0X0.] | |.Y.^.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.<.<.< i.F.F.JX;X,X3 Q.r.i.sXtXu.@.).b m.g.G.2. &.3X=.d ].z.cXl.zXxXx 3.c.c.c._._._._._ nX0X0 | |.Y.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.<.<.< i.F.J.JX;X, # Q.rX7.i...WXdXg.l.` 5Xr.G.2. &.3X=.d ].z.z < < < < < < < < < < ' '.zX8._._._X0.p.Y.w.w.w.w.w.w",
+".w.w.w.w.w A.< i i.F.J.JX;X, # QX5X7.i.sXtXu.k.).b m.N l.qX<. &.3X=.d ] x <.#.#.#.#.#.#././.# ` ` ` ` x ' 'X8X8 v = 8.w.w.w.w.w",
+".w.w.w.w.w i.F.F.J.JX;X,X, # QX5X7.i.sX2XuXdXg.*.` 5.}.E.HX<. X6.3 I.d ] `./ , , , , , , , , , , z z./.t./ ` ` ' ' [ =.w.w.w.w.w",
+".w.w.w.wX;.F.J.JX;X;X, #X3 QX5X7.i.sX2.WXdXg.l.b.{.N V.!.HX<X ).3X=.d q , ,XaXaXaXa.!.!.!.~.~.~ , , ,.e , ^ ^.t ` ' ' =.w.w.w.w",
+".w.w.w >.JX;X;X;X,X, #X3 Q.rX7.i.s...WXd.k.).b m.N.} C.~.HX<X X6.3X=.d q ,.~.!.!.!.!.!.!.E.E.E.Q.!.!X4.~ ! !.e.e ^.t ` `.D.w.w.w",
+".w.w.w #X,X,X, # #X3 QX5.rX7.i.sX2.WXd.k.).b.` 5 B CXX.!.HX<X X6.3X=.'.X.!.!XrXrXrXrXrXrXr - - l l.q.E.E WX4X4 ! a.e ^X: Y.w.w.w",
+".w.w.w # # #X3X3 QX5.rX7.i.i.sX2.WXd.k.).*.`.{ B VXXXX.!.qX<X ) TX=.'.X.E l.g.g.f.f.f.f.f.f.g.g k k -X1.q.q.q WX4 ! !.e ^.w.w.w",
+".w.w.> Q Q QX5X5 (X7.i.i.s..XtXuXd.k.).*.`.{ B V CXXXX.Q.GX<X X6.3X= { $X1.gXq.U.a.a.a.a.a.a.a.U.U.U.U.T.0X1X1.q.q W.H ! a ].w.w",
+".w.w.r.r ( (X7.i.i.i.s..Xt.WXuXdXg.).b.`.{.N V C C C C.E.GX<X ).3X= { $.T.U } } }X9X9X9X9X9 h h h.6 E E.U.9.U.0X1.G.q WX4 a.w.w",
+".w.|.i.i.i.i j j.s..Xt.WXuXd.kXg.l.b.`.{ B V C C C C.} l.G.2X X6.3X= { $ E }X9X9X9X9 g g g g g gX>X> O h.6.6 E.8.0X1X1.G.q.H ].w",
+".w.1.s.s......XtXt.WXuXd.@Xg.).*.b m 5 B V C C C V.}XqX1X-.2X ).3X= / L hX9 g.I.I.I.I f f f.I.I.I.I g gX> O O.6 E.8.0X1.G.q ].w",
+".w.WXtXtXt.WXuXuXuXd.kXg.).l.b.`.{.N B V C C C V.}Xq B -.9.2X ).3.- / LX> g f.L.L.L.L.L d.L.L.L.L U U U f.IX>.4 O.6 @.9.0X-.H.w",
+".wXuXuXdXdXd.@.kXgXg.l.*.b.` m 5.N.} CXXXX C C.}Xq B B.0 @.2X ).3.- / L g f.L d * * * * * s * *.K.K d d.L U.1.IX>.4 O.6 @.0X-.w",
+".!XgXgXgXgXg.).l.*.b.b.` m 5.N.} V CXXXXXX C.}Xq B B M.0 p.2X ).3.- /.' U.L * s s % % % % % % % % s s s.K d d U.1 o.4 O.6 @.9.G",
+"XX.*.*.*.b.b.` m }.U.U.f.gXr l.E.!.~.!.!.Q.E lX1 -.0.0.9.| r. & XX*Xw {Xz y t.K . . . . . . . . t t t J J yXzXz U.1.S.S.4 p @X-",
+" C m m m m 5 5.f.0.0.0.0.G.G.q.H.H.H.H.q.G.G.GX-.9 @ p.| L e., & X.h +.$Xz _.jXf > > > > > > > > > >.j.j.j _ _.&Xz y.1 o.S.4 O.9",
+" V 5 5.N.N.} C.| { ;X<.2.2.2X<X<X<X<X<X<X<X<.2.2.2.2.2 r e.h K.7.y.,.- ~.2 r e e e e e e e r r r r.2 + /.'Xz y UXz.S.4 @",
+" C.V.V C CXy.!.' .-XOX . . . . X X X X X X X X X X X . ., K.y.y.y R &.,. X X ZX XO ZXOXOXOXOXiXiXiXiXiXi.h.h.2 {Xz J y y U.S O",
+"XyXXXXXXXX.! ! { ~.A b.u & & &X6 )X6X6 )X6 )X6 ) ) ) ) & &.7.y.y.y X.7 KX6.(.u.u.(.u.u.u.u b b b b b b b b.,X /.$ t t t y.1.4",
+"X+X+X+X+X+ , aXp.h.,.7.7.3.3.3.3.3.3.3 T.3.3.3.3.3.3.3 X X.y.y.y.y.y.y X T T.5.5.5.5 T T T.5.5.5.5.7.7.7.7 K.u ~ /.$XfXf . t y.S",
+"XaX+X+XaXa , z $Xw ~ IX=X=X= IX=X=X=X=X=X=X=X=.-.-.-X*.h., R X.y K. .AX*X*X*X*X*X*X*X*X*X*X*X*X*X*.-.-.- I ~ +.$ _.o.Z.Z . J.1",
+"X#.O.O.O.OX#.# u q $.d.d.d.d.d.d.d.d.'.' { { { / / / /Xw +.- &.7.y. ~ 6 6Xw 6 6 6 6 6 6 6 6 6 6 6 6XwXwXwXwXp >.o 9.o.o.Z t y",
+" <X#X#X#X#XhXh ' u u ] ] ] ] ] ] q q.X.X $ $ $ L L L.' {.$ ~., K X.A XwXpXp ; ; P P P P P P P P P P P ; ; ;Xp.o 9 9 9 9.o.Z . J",
+" v.#.#.#XhXhXh.% < 2 '.z.z.z x ` , ,.!.EX1.T E hX> g UXzXz.2. X6 TX* 6XpXe.>.:.;.;Xc.xX&XkXkXkXk 1 1.xXc.;.:.:.>.>.>.>Xe 9.o.Z J",
+".pXhXhXhXhXh.%XlXl.z.z.c.c.z <./ ,.~.! l.g.U }X9 g f.L y _ rX .( TX* 6Xp.>.MXcX& H HX$ G G G G G G GX$ HX&.x.;.M.:.:.>Xe 9 9.o t",
+".w.%.%.%.%.%.%X%XlXlXlXlXl <.# ,Xa.!Xr.gXq }X9 g f.L * t.j eX .u.5X*Xw ;.:Xc H G w w w 0 0 0 0 0X@ F F.+ GX$Xk.x.;.:.:.>Xe 9.o.w",
+".w.zX%X%XlXlXlXlXlXl.z.z.z <.# ,Xa.!Xr.g.U }X9.I.L d s.KXf e Z.u.5X* 6 ;.;X& G w w 0 0 S S.C.CXo S S 0 F.+ GX$Xk.x.;.:.>.> 9.o.w",
+".w 8XlXlXlXlXl.zXxXxXx.=Xx <.# ,Xa.!Xr.f.a }X9.I.L * s . > eX .(.5X* 6 P.; H w w 0 0 S.C.C A A A A.CXo D F.+ GXj 1Xc.:.:.>XeXz.w",
+".w 8XlXxXxXxXx.=.=.= 3 3Xx <.# ,Xa.!Xr.f.aX9X9.I.L * % . > XO.u.5X* 6 PXc H w 0 0.C.CX..B.B.B.B.B.B AXo D F.+X$Xk.x.;.:.>Xe _.w",
+".w.w._.=.=.=.= 3 3 3 3 3 3 <.# ,.!.!Xr.f.aX9 g.I.L * % . > Z.u TX* 6 P.xX$ w 0 S.C.B.B 7 7 N N N 7.B AXo DXs GXj 1.;.:.>Xe.w.w",
+".w.w 8.= 3 3 3 3 3 3 4 3.c <.# ,.!.!Xr.f.aX9 g f.L * % . > XO.u TX* 6 PX& G 0 S.CX..B 7 N.[.[.[.[ N 7.B A SX@.+X$Xk.;.:.: _.w.w",
+".w.w.w 3 3 3 3 3 4 4.m._.c <./ ,.!.EXr.f.aX9 g f d * % . > XO.u TX* 6 PXk G 0 S.C.B 7 N.[.n.n.n.n.[ N 7X.XoX@Xs GXk.x.M.:.w.w.w",
+".w.w.w.] 3 4.m.m.m.m.m.m.c <./ ,.~.E -.f.aX9 g f.L s % . > eXO b.5X* 6 PXk G 0.C A.B 7.[.n.v c c.v.n.[ N.B.C DXs GXk.x.M.>.w.w.w",
+".w.w.w 8.m.m.m.m.m.m n.m._ <.# ,.~.E -.g.a h g.I.L * % . > eXO b.5X* 6 PXk G 0.C A.B N.[.n c c c c.v.[ N.B A DXs GXj.x.M.o.w.w.w",
+".w.w.w.w |.m.m n n n n n._ < ` ,.~.Q l.g.U h g.I.L * % . > eXi b.5X* 6 PXk G 0Xo A.B N.[.n c c c c.v.[ N.B A DXs GXk.x.>.w.w.w.w",
+".w.w.w.w.w.] n n n n n n._ ' ` z ,.! l k.U hX>.I.L.K % t > eXi b.5X* 6 P 1 GX@ S A.B N.[.n.v c c c.n.[ NX.Xo DXsX$Xk.M.w.w.w.w.w",
+".w.w.w.w.w 8 n n n nX0 n._ ' ` z ,.!.q k.U.6X>.I U.K s t > rXi b.7X* 6 P 1 G F S.C.B 7 N.[.n.v.v.n.[.[.BX.XoX@.+X$Xk.R.w.w.w.w.w",
+".w.w.w.w.w.w | nX0X0.]X0._.z `./ ,X4.E -.U E O g U d s t.j rXi b.7.- 6 P.xX$ F 0Xo A.B 7 N.[.[.[.[.[ 7X. A DXs.+Xj.M.w.w.w.w.w.w",
+".w.w.w.w.w.w.w |.].].]X0 nX8 x.t.e.~.EX1.T E h g U d s J.j rXi b.7.-Xw ;Xc H.+ F DXo A.B 7 N N N N.BX. A SX@ :X$.x.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.^ |.].].]X0._ './ , ! W.q.0.U.6X> f.L.K J.j rXi b.7.-Xw ;.;X& G.+ F DXo AX..B.B.BX.X. A SX@Xs G 1Xp.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.^ | | |X0._ ' ` ^ !X4.qX1.9.6 O.I U d y _.2.h., K IXw ;.:.xX$ G.+ F D SXo.C A AXoXo DX@Xs G 1Xp.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.^.Y | |._X8 ` ^.eX4.qX1.U E OX>.1 dXz _ +.hX .u ~XwXp.:.;XkX$ G.+XsX@X@ D D D DX@Xs : G 1 /.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.^.Y |X0X8 '.t.e ! W.q.0.8.6.4.I UXz.& /.2 ~ +Xp.o.>.M.xXkXjX$ G.+XsXsXsXsXs.+.+X$ 1Xp.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.^.Y.p v ' ` ^ aX4.qX1.0 E OX>.1 UXz.' { / /.$ > 9.>.:.;.x 1XkXjX$ G G G GX$X$Xj.xXp.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.Y = [ '.t.e ! W.GX1.8.6.4 o.1 yXzXz.$.$ _.o 9.>.:.:.;Xc.x 1XkXkXkXjXkXkXk.M.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w 8 = ' ` ^ !.H.qX1.0 @ O.4.S.1 y J tXf.o 9 9.>.>.:.:.:.;.;.;.x.x.x.x.M.R.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w = `X:.e ! W.GX1.9.6 O.S o U y tXf.Z.o 9XeXe.>.>.:.:.:.:.M.M.M.>.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.D Y ^ aX4.q.G.0 @.6.4.SXz y t ..Z.o.o 9 9Xe.>.>.>.>.:.:.>.o.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w ] a.H.qX-.0 @ p.4.S U y t ..Z.Z.o 9 9 9XeXeXe _.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w ] ].HX-.9 @ O.4.S.1 y J t ..Z.o.o.oXz _.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w",
+".w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.GX-.9 @ O.4.S.1 y J J t.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w"
+};
diff --git a/arts/builder/pics/Synth_AMAN_PLAY.xpm b/arts/builder/pics/Synth_AMAN_PLAY.xpm
new file mode 100644
index 00000000..3ad46f6e
--- /dev/null
+++ b/arts/builder/pics/Synth_AMAN_PLAY.xpm
@@ -0,0 +1,316 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 245 2",
+/* colors */
+" c #B1B1B1",
+" . c #BFBFC2",
+" X c #ADADAD",
+" o c #A9AAB3",
+" O c #ABABAB",
+" + c #323E7D",
+" @ c #5F6792",
+" # c #71789D",
+" $ c #2F3A7A",
+" % c #3E4C8C",
+" & c #A5A5A5",
+" * c #3A4488",
+" = c #273272",
+" - c #8D93B5",
+" ; c #78787C",
+" : c #253070",
+" > c #616B97",
+" , c #344082",
+" < c #232E6E",
+" 1 c #313C7F",
+" 2 c #B0B5CA",
+" 3 c #1F286A",
+" 4 c #959595",
+" 5 c #1C2667",
+" 6 c #5F6BAC",
+" 7 c #696A6D",
+" 8 c #374288",
+" 9 c #8D8D8D",
+" 0 c #36417D",
+" q c #6F79AB",
+" w c #43518D",
+" e c #1F2A6D",
+" r c #1E286C",
+" t c #414F8B",
+" y c #2D3774",
+" u c #1A235E",
+" i c #9599AF",
+" p c #D1D2D6",
+" a c #64666B",
+" s c #475394",
+" d c #777777",
+" f c #767DA1",
+" g c #536299",
+" h c #2F3B79",
+" j c #8E8F94",
+" k c #2A3574",
+" l c #5D68A6",
+" z c #4B5891",
+" x c #50598C",
+" c c #273171",
+" v c #575D7F",
+" b c #222D6C",
+" n c #212B6B",
+" m c #303B7D",
+" M c #404B90",
+" N c #1D2767",
+" B c #3C478C",
+" V c #4C5A95",
+" C c #38447E",
+" Z c #38427E",
+" A c #343E7A",
+" S c #858CAF",
+" D c #42508B",
+" F c #2E397E",
+" G c #1D276A",
+" H c #404E89",
+" J c #1C2769",
+" K c #303A76",
+" L c #2C377C",
+" P c #3E4C87",
+" I c #C7C7C8",
+" U c #AFB0B7",
+" Y c #E4E5EB",
+" T c #29326F",
+" R c #384481",
+" E c #DCDDE3",
+" W c #303C79",
+" Q c #3E4C8A",
+" ! c #3D4A89",
+" ~ c #414B83",
+" ^ c #3A4886",
+" / c #686971",
+" ( c #7B84A8",
+" ) c #515C8C",
+" _ c #656F99",
+" ` c #7880A5",
+" ' c #4A578F",
+" ] c #424C91",
+" [ c #202A69",
+" { c #3E488D",
+" } c #2C3878",
+" | c #1B2464",
+". c #797A7E",
+".. c #3A477F",
+".X c #9D9D9E",
+".o c #39457E",
+".O c #47558F",
+".+ c #D0D0D0",
+".@ c #212C6D",
+".# c #1E286A",
+".$ c #CACACA",
+".% c #283277",
+".& c #3B4783",
+".* c #253074",
+".= c #485793",
+".- c #BEBEBE",
+".; c #222C71",
+".: c #44538F",
+".> c #BCBCBC",
+"., c #6974B0",
+".< c #BABABA",
+".1 c #1E286D",
+".2 c #3E4D89",
+".3 c #848AA6",
+".4 c #5F6585",
+".5 c #4F599D",
+".6 c #B4B4B4",
+".7 c #B2B2B2",
+".8 c #394784",
+".9 c #ABADB5",
+".0 c #34417F",
+".q c #ACACAC",
+".w c #87878B",
+".e c #58649F",
+".r c #AAAAAA",
+".t c #414D8F",
+".y c #2D3978",
+".u c #6F6F70",
+".i c #57608A",
+".p c #A0A0A0",
+".a c #666871",
+".s c #283373",
+".d c None",
+".f c #CFD0D8",
+".g c #364184",
+".h c #465197",
+".j c #242F6F",
+".k c #BBBCC1",
+".l c #9A9A9A",
+".z c #313D7F",
+".x c #989898",
+".c c #A8A8AB",
+".v c #4D5480",
+".b c #52609C",
+".n c #A3A4A6",
+".m c #4E5E98",
+".M c #2B3579",
+".N c #6B739A",
+".B c #293577",
+".V c #293377",
+".C c #273175",
+".Z c #495893",
+".A c #394680",
+".S c #475691",
+".D c #717482",
+".F c #E0E1E5",
+".G c #42508C",
+".H c #DADBDF",
+".J c #1D276B",
+".K c #979DBB",
+".L c #8088AB",
+".P c #2C3673",
+".I c #5C6281",
+".U c #242F75",
+".Y c #3C457C",
+".T c #33407D",
+".R c #747474",
+".E c #41508E",
+".W c #B8B9BA",
+".Q c #646FAD",
+".! c #2E3A78",
+".~ c #808083",
+".^ c #2C3876",
+"./ c #2B3675",
+".( c #293473",
+".) c #384485",
+"._ c #242E6E",
+".` c #45518B",
+".' c #424F88",
+".] c #465082",
+".[ c #414D87",
+".{ c #2D387A",
+".} c #9FA2AB",
+".| c #2B3678",
+"X c #384288",
+"X. c #171F57",
+"XX c #343E84",
+"Xo c #DEDEE2",
+"XO c #353F7B",
+"X+ c #2F3A7F",
+"X@ c #1C2669",
+"X# c #2F3975",
+"X$ c #3E4B87",
+"X% c #D7D8DB",
+"X& c #C4C4C5",
+"X* c #4A5996",
+"X= c #36437F",
+"X- c #48548A",
+"X; c #202A70",
+"X: c #F1F1F1",
+"X> c #1F2A6F",
+"X, c #515BA0",
+"X< c #B4B4B5",
+"X1 c #3B4987",
+"X2 c #4C579B",
+"X3 c #7D7D7F",
+"X4 c #B2B2B3",
+"X5 c #3E4880",
+"X6 c #384584",
+"X7 c #495598",
+"X8 c #364382",
+"X9 c #5661A8",
+"X0 c #434F92",
+"Xq c #374079",
+"Xw c #53597A",
+"Xe c #A5A7B0",
+"Xr c #3E498D",
+"Xt c #5966A4",
+"Xy c #1E296A",
+"Xu c #1D2769",
+"Xi c #C9C9C9",
+"Xp c #929293",
+"Xa c #3B458D",
+"Xs c #3D4A85",
+"Xd c #4C5C97",
+"Xf c #E6E7EC",
+"Xg c #D4D5D7",
+"Xh c #C3C3C3",
+"Xj c #C1C1C1",
+"Xk c #232D72",
+"Xl c #465491",
+"Xz c #455490",
+"Xx c #212B70",
+"Xc c #34407C",
+"Xv c #43528E",
+"Xb c #CCCDCF",
+"Xn c #1F296E",
+"Xm c #323E7A",
+"XM c #1E296D",
+"XN c #525EA0",
+"XB c #313C79",
+"XV c #B7B7B7",
+"XC c #676A79",
+"XZ c #2A3472",
+"XA c #7C7C7D",
+/* pixels */
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d c.%.V.V.%.C.U.U.;XnXy N.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.P +X 8XXX+ L L.V.%.U.UXk.;.;XxX;Xn | u.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.dX1X0 M BX 8XXX+ L L.V.%.U.UXk.;.;XxX>X>XnXn r u.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d ZX,.5X7.h MXaX XXXXX+ L L.V.%.U.UXk.;.;XxX>X>XnXM.1.1 rX@ u.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.dX9X9X,.5X7X0 MXaX XXXXX+ L.M.V.%.U.UXk.;XxXxX>XnXnXM.1 r r r.J 5.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.dXd 6 6X9X,X2.hX0 MXa 8XXXXX+ L.M.V.C.*.UXk.;XxXxX>XnXnXM.1 r r.J.J.JX@ u.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.,., 6X9X9X,X2.h ] {Xa 8XX 1 F L.M.V.s = c :.;XxX;X>XnXnXM.1 r r.J.J.J G G 5.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.`.,.,.Q 6X9XN.5X7.h ] {Xa 8XX 1 F L m 0XOXOXB K.s.;XnX>XnXn.1 r r r.J.J G G G G 5X..d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d z.,.,., 6X9X9X,X2.hX0 MXaX 8XXX+ m Z x # f `.N @ ~ c.@XnXnXM.1 r 3 [ G G G G GXuX@ 5X..d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d V.,.,.,.Q 6X9X9X,X2.hX0 MXa 8XX 1X+ Z.' (.fX% E .Xe @ y.@XnXnXM r e._ T b rXu G GXuX@X@ 5X..d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d z.,.,.,.Q 6X9X9X,X2X7.h M {Xa 8XX , R.i ( U E.f I o j.4 y.@XnXnXM 3._Xq ).Y T [XuXu JX@X@ 5 5X..d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.`.,.,.,.Q 6X9X9XN.5X2.hX0 MXaX XXXX.&X-.L.f EXf.$ X j. Xw.P nXnXn.1 [ T ) - @Xq T.#XuXuXuX@ 5 5 5X..d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.,.,.,.Q 6 6X9XNX,X2.hX0 M {Xa 8.gX$ @ S 2 EXo.FXh &.w.RXwX# T.@ e r.@._.Y @ @ @X5 T n.# GXuXu 5 5 5.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.,.,.,.Q 6X9X9X9X,X2X7.h ] MXaX .gX$ ' S.f E YXo.H.>.X.~ / v KXBXm.(Xx.@.@.PXq @ i @XqXZ e 3 r.#.#XuXu |.d.d.d.d.d.d",
+".d.d.d.d.dXd.,.Q 6 6X9X9XNX,X2X7.hX0 MXaX *.[ > S 2X%Xb ..$XgXV.l.~ / vXqX- _X-Xm.( < c y.] @ > _.] c.@ e e 3 3Xy.# u.d.d.d.d.d",
+".d.d.d.d.d 6 6 6X9X9X9XNX,X2X7.hX0 M B *X H z S.fX%.H.W.xX4Xb.6.l.~ / v.Y >.K fX- A : : :X#.Y.N.9 @ K._.@.@.@ n nXyXu.d.d.d.d.d",
+".d.d.d.dX9 6X9X9X9XNX,.5X2X7 sX0.tXrX1 !.G > S 2.H IX4.p 9.qXbX4.l.~ /Xw A.v _ # ( x.y = :XZXq _.9 _XqXZ < < < <.@ n nXu.d.d.d.d",
+".d.d.d ZX9X9X9XNX,X9 lXtXt.e.b.b V V z z ) -.f.H.H.6 9.wX3 &.$.7.l.~ /.v yXq ~ # 2.N 0.(.C.sXB @.9.NX5 K c :.j.j < <.@.@ |.d.d.d",
+".d.d.dX,X,X,X,.5XN q.K.K.K.K.K.K.K - - -.K 2 EXbX<.xX3X3XA.n.$ .x.~ /Xw K A.o.N 2 f.[XB.s./.y.].N.N.N.]X# c c : :.j < b [.d.d.d",
+".d.d.d.5.5X2X2X7XN -X% EXfXfXfXfXfXf YXfXfXf Y.W 9.~.R dXA.pXi .x.~ /XwXm AXO _ 2.L ).&.|.|.BXO ~.N.9 _XqXZ.s = c : :.j <.d.d.d",
+".d.dX1X7X7.h.h s.b - E YXf Y.FXoXo E.H.H EXoXoXVXp.wXA.~.w &Xi .x.~ /Xw AXm $X- # `.L ) +.y.|XBX5 @ i @ Z.P k.(.s = c : : N.d.d",
+".d.dX0.hX0X0 ] ].m.KXfXf YXoX%XgXg p.+.+.+Xg.HXV 4 9.w.w 9.q.$ .x.~ /XwXOXm.{ Z.] f 2.N.& $.{ K.o.i (.i.o.^.|.B k.(.s = c.j.d.d",
+".d.P M M M M {Xr V -Xf.FXoXg.+Xb.$Xi I IXiXgXo p IXj.-XjXj.$.+.6.x.~ /Xw 0 W.{XO ~ _.K _X5XB m W.o @ i > ~Xm } }././ k.(.s c [.d",
+".d + BXaXaXaXa *Xl -XfXoXgXbX&XhXj.-.-.-Xj p YX:X:X:X:X:X:XfX%XV.x.~ /Xw Z h m WX5 @.L @ ~Xm mXB.. _ 2 #.].o h.y } }./ k.(.s [.d",
+".dX X X X 8 8.).` S YXoXg.$XjXj.-.-.>.-.-.+.F YXfXfXfXfXfXoXgXV 4X3 /Xw.oXB.z +X5 >.K.N.' Z +.TX= x # # # xXc h.!.y }.^./ k =.d",
+".d 8 8XXXXXXXX ,.[ S Y E.+XiXj.-.-.<.<.<.-XbXo.H.H.HX%X%X%Xg p.6 4X3 /Xw.o +.z.TXs.N 2 fX- ~ , ,.0X5X- # 2.NX5Xm $ $.!.y.^./ k.d",
+" cXXXXXXXXXX 1 +X$ S Y.H.+ I.-.>.<.WXV.W.<XiXgX& X.c O X.-Xb 4X3 / v.&.T ,.0.8 ) f f f ).&X8X8...' _ i _ ~Xm + W $.!.y.^./XZ",
+".%X+X+X+X+X+ F mXs.L Y.HXbX&.<.<.WXVXVXV.<X&.+.r.wX3 dXA.~ &X& X 4X3 / v.&.0X8X8.).[ x f 2 #.' RX8X=.[ @.3 @.[ 0 + +Xm W h.y.y k",
+".V L L L L L L.{.&.L YX%.$Xj.WXVXVX<.6XV.WXhXb &X3 d.u.RXA.pXh.q 4X3 / vXs.0X8.).)XsX-.N.K.N.` R.).A.' @.L @.' 0.0.T + + W h.!.^",
+".V L L L.M.M.M.| R (.FX% I.-XVXVX<.6X4X<XVXj.$.p d.u a.u.R.lXj O 4X3 / vXsX8.).).).&.` > S >X-.8 ^.&.' @.3 >.`X=.0.0.T +Xm W h.^",
+".%.V.V.V.V.V.%.B Z (.FXg I.-X<.6X4.7.7.6XVXj.$.p d.u a.u.R.lXj.rXpX3.a v.[ R ^ ^X1.&.` > S _.OXsX1.&.` @.L >.`.AX8X8.0.T + + W.!",
+".C.%.%.%.%.C.C.s 0 (.FXgX&.>.6X4.7 X4X<.-Xi.p d.u a.u.R.lXj.rXpX3.a v.[.8X1X1 !XsX- > S _ 'X$ !XsX- >.3 >X-.AX6X8X8.0.T +Xm h",
+".U.U.U.U.U.*.U = A `.F pXj.<.7 .7.6.- I.X.R.u a 7.R.lXj.rXpX3.aXw.[.8 ! ! QX$.O > S _ z.[ Q PX- >.3 >X-.&.8X6X8X=.0.0 + W",
+".U.U.U.U.U.U.U :Xm ` E pXj.W X4.- I.X.R.u a 7.R.xXj.rXpX3 /Xw P.& Q % %.2 ' _ S _ z H.t.[ ' > S _X-Xs ^.8X6X8X=.0XcXm",
+".;XkXkXkXkXkXk :XB f E pXjXV X X .7.- I.nX3 d.u dXA.pXj.rXp. .a v.'X1 % %.t.` ) #.K # z D.E H ' _ S _ 'XsX1 ^.8X6X8X=.0 +",
+"Xn.;.;.;.;.;.;.j K f E p.-XV X X X X .7.-Xi.c.w.~XA.~.w &Xj.rXp. .a.I.` P %.t.E z g ( 2 f z wXv D z _ S _ z PX$X1 ^.8 RX8.0Xc",
+"Xy.;.;.;XxXxXx bX# # E.+.-XV X X X.q.q X Xj.+ I.>.WXV.W.<XjXi XXp. .a.IX-.2.E.E.O > ( ( ( >.ZXl.:.O ) #.K.NX- P QX$X1 ^.8 RX=Xc",
+" NXxXxXxXxXxX; nXZ.N EXb.-X< X.q.q O O X X&X%.FX:X:X:X:X:Xo.+ Xp. .a.I.O H.E w V ` 2 ( g VXlXlXl V g ( 2.NX-.[ Q Q !X1.8.A RXc",
+".dX;X>X>X>X>X>.@ y # EXb.>.6.q.q O O.r X XjXg.H.F.F.FXoXoXgXb Xp. .a.I.O DX0.:.m f.K f g z.=.Z V > ( ( ( @.: t t Q PXs ^.8 R.d",
+".dXnX>X>XnXnXn.@ K ` EXb.<X4.q O O.r.r.q Xj.+.+.+.+.+.+.+Xb.$ XXp. .a.I '.GXl.O g # -.N g.ZX*.Z g ` 2 ( g z.: w.G t.2X$X1.8.A.d",
+".d |XnXnXnXnXn b K f E.$XV X & & & & &.c O.<.$.W.c &.p.n &X<X&.rXp. .a.4 '.:Xl z g `.K f g zX* V g f.K f g 'Xz.: w t Q PXs ^Xm.d",
+".d uXnXMXMXMXM nX# f.H I .r.p.p.p.p.p.n &X<Xh.pX3 d.u dXA.X.- &Xp. .a.4 '.SXl.m.e.L 2 ( g VXd V.e # -.N.m.OXlXzXv.G t QX$ ^Xq.d",
+".d.d r.1.1.1.1 [ y.N.kXe j.w.w.~.~.~.~.w 9.n.W.lXA.R 7.u d.x.- & 9. .a.4 ' z V _.L -.K q.b.m.m.m.e `.K # g.O.SXl.: w t.2X$.&.d.d",
+".d.d u.1 r r r [.P.4.} j.D.u / / / / /.u d j 4 ;.u a 7.u 4.> & 9. .a.4 z V.m ( 2.K q.e.m.m.m g >.L 2 ` g z.=Xl.: w t.2 PXq.d.d",
+".d.d.d r r r rXy._.Y.i vXwXwXwXwXwXwXwXw v.D j j 9X3.u.u.u 4.< & 9 ;.a.I z.m g.L 2 - l g.m.b.e.N.L.L.L _.m.Z.=.SXzXv.G H P.d.d.d",
+".d.d.dX@ r.J.J G r._ T TXZ.P yX# K KXmXq.Y v.D.w & 9 d.R.u 4.< & 9 ;.a.I '.m @.L 2.L.e.m.b.bXt.L 2.L > gXdX*.Z.SXzXv.G HXs.d.d.d",
+".d.d.d u.J.J.J.J G G 3 3 [ n b._ : =XZX#XO.] v.D.w 9 9.~ ;.l.< & 9 ; a.4 ) > ( S.K q.b.m.b g l.L 2.L.e.mXdX*.Z.SXzXv.G H...d.d.d",
+".d.d.d.d 5.J.J G G G G G r e.@.j : =.s.B } 0X5 v.D.w.nXp.~.p.> & 9 ; a.4 g ` 2 - q.e.m.m.b.e _ S 2 (.eXdXdX*.Z.SXzXv.G P.d.d.d.d",
+".d.d.d.d.dX@ G G G G G G r e.@.; :.*.s.B.| W 0.] v.D.w j.x &XV.p 9 ; a.4 ) _.L q.e.b.m.b.e.N (.L.L _ gXdXdX*.Z.SXz w H.d.d.d.d.d",
+".d.d.d.d.d u G G G GXu G r e.@ < :.*.s.B.|.y $ Z ~.I.D j X .X 9 ; a.4 z g.e.mXdXd.m g > (.K ( >.e.mXdXdX*.=Xl.: w...d.d.d.d.d",
+".d.d.d.d.d.d 5 GXuXu JXu.# e.@ < : c.C.B.| }.!Xm.o.v.I.D j.X .X.w d a.4 ' ' z.=X* V.m > ` ` ( _ g.mXdXdX*.Z.S.O.: H.d.d.d.d.d.d",
+".d.d.d.d.d.d.d 5X@X@X@Xu G 3.@ <.j :.C k.B }.{ $ +...].I.D j X.l.w d a.I ' wXl.=.Z z g f.K ` > g.mXdXdX*.Z.=.SXz D.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.dX. 5X@X@X@Xu r e.@.j : =.(.B.|.y $ mXc...v.I.D.w.~ d / a.IX- DXlXl.=.=Xd > # > gXdXdXdX*.Z.=.SXz w.Y.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.dX. 5 5 5Xu.# e.@ < : c.s k.|.{ $ m +.0X5.] vXC.a a a a vX- D.:XlXl.S.= V.mXd VX*X*X*.Z.=.SXl w.Y.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.dX. 5 5 5.# 3.@ <.j c.s k.| }.! $ + + 0X5.v v v v v v x.` D w.:XlXl.S.S.S.Z.=.Z.Z.=.S.SXz w.Y.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.dX. 5 5Xu 3 n <.j : =.(.B }.y $ m +.T.0.A ~ ~ ~.[.'.' Q t.G w.:XzXlXl.S.S.S.S.SXl.OXz w.Y.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.dX. 5XuXy n.@ < : c.s k./ }.! $ + +.0.0 0 C.A.&.&XsX$ Q t.G wXv.:.:XzXzXzXzXz.:.: D.Y.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d |.#Xy n <.j : =.(./ }.y $ W +.T.0X8X8X6.8 ^X1X$ Q Q t t.G w wXvXvXvXv w w H.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d uXu n.@ < : c.s k./ }.! $Xm +.T.0X8X8X6.8 ^X1 ! P.2 Q t t t.G.G.G.G H...d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.dXu.@ b.j : =.( k.^.y.! W + +.T.0X=X8X6.8 ^X1XsX$ P Q.2.2 H H H P.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d | [ < : c.s.(./.^.y h WXm +.T.0X=X8 R.8.8 ^X1XsX$X$ P PXs...d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d N.j c.s k./.^.y h W + +.0.0X=X8 R.A.8.8 ^ ^.&Xq.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d [ [ = k./.y.! h WXm +Xc.0.0X= R R.AXmXq.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.dXZ k.^.^.! h WXm +XcXcXc.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d"
+};
diff --git a/arts/builder/pics/Synth_ATAN_SATURATE.xpm b/arts/builder/pics/Synth_ATAN_SATURATE.xpm
new file mode 100644
index 00000000..153b5bfd
--- /dev/null
+++ b/arts/builder/pics/Synth_ATAN_SATURATE.xpm
@@ -0,0 +1,310 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 239 2",
+/* colors */
+" c #485896",
+" . c #364281",
+" X c #33407E",
+" o c #327F37",
+" O c #313E7C",
+" + c #31694A",
+" @ c #2E3A79",
+" # c #8088AF",
+" $ c #4F5AA0",
+" % c #1D2865",
+" & c #273272",
+" * c #253070",
+" = c #455296",
+" - c #838CB5",
+" ; c #2E3A7C",
+" : c #1E2869",
+" > c #2A3678",
+" , c #283276",
+" < c #273275",
+" 1 c #3A4781",
+" 2 c #475591",
+" 3 c #323E83",
+" 4 c #45538F",
+" 5 c #747AA6",
+" 6 c #212C6F",
+" 7 c #5363A0",
+" 8 c #42518C",
+" 9 c #1E286C",
+" 0 c #2D387E",
+" q c #2B367C",
+" w c #29347A",
+" e c #1A235E",
+" r c #384582",
+" t c #475794",
+" y c #232E74",
+" u c #465593",
+" i c #357943",
+" p c #35417F",
+" a c #233F56",
+" s c #656FB8",
+" d c #20345D",
+" f c #4D599D",
+" g c #2B3775",
+" h c #394786",
+" j c #768C9A",
+" k c #848DB5",
+" l c #3A478A",
+" z c #232D70",
+" x c #222D6F",
+" c c #313B81",
+" v c #1E296B",
+" b c #316D45",
+" n c #2E397E",
+" m c #405089",
+" M c #414E8A",
+" N c #2D397D",
+" B c #1D276A",
+" V c #2D3C73",
+" C c #2A357A",
+" Z c #4C5C98",
+" A c #293379",
+" S c #283378",
+" D c #4B5A97",
+" F c #4A5A96",
+" G c #2A3F66",
+" H c #263176",
+" J c #485894",
+" K c #242F74",
+" L c #475693",
+" P c #232D73",
+" I c #455491",
+" U c #33427C",
+" Y c #202B70",
+" T c #2D3876",
+" R c #3C4A88",
+" E c #3B4887",
+" W c #2B3674",
+" Q c #374483",
+" ! c #222C6B",
+" ~ c #2F3C7B",
+" ^ c #3D4C8C",
+" / c #1C2665",
+" ( c #4B569D",
+" ) c #28396A",
+" _ c #48529A",
+" ` c #747CA4",
+" ' c #434E95",
+" ] c #212C6D",
+" [ c #1C2668",
+" { c #4E5D99",
+" } c #293478",
+" | c #2B5452",
+". c #273276",
+".. c #374289",
+".X c #253074",
+".o c #485793",
+".O c #222C71",
+".+ c #212C70",
+".@ c #44538F",
+".# c #737AA6",
+".$ c #202A6F",
+".% c #43518E",
+".& c #1F2A6E",
+".* c #2F3A81",
+".= c #1D286C",
+".- c #3D4B88",
+".; c #37843C",
+".: c #435191",
+".> c #333F7E",
+"., c #414F8F",
+".< c #303D7B",
+".1 c #515DA2",
+".2 c #1E2B66",
+".3 c #2D3978",
+".4 c #2D5B50",
+".5 c #2C3777",
+".6 c #3B4989",
+".7 c #1B2563",
+".8 c #293574",
+".9 c #3A8F38",
+".0 c #294C56",
+".q c None",
+".w c #263171",
+".e c #242F6F",
+".r c #314B6B",
+".t c #404B91",
+".y c #1F296A",
+".u c #1C2767",
+".i c #2B3779",
+".p c #1B2566",
+".a c #3A458B",
+".s c #283376",
+".d c #384389",
+".f c #364187",
+".g c #353F86",
+".h c #26346A",
+".j c #757BA7",
+".k c #44528E",
+".l c #7379A5",
+".z c #1E296C",
+".x c #1D276B",
+".c c #404E8A",
+".v c #2C377D",
+".b c #4E5E9B",
+".n c #3E4C88",
+".m c #2A357B",
+".M c #283379",
+".N c #263177",
+".B c #28465B",
+".V c #475694",
+".C c #7684A1",
+".Z c #455492",
+".A c #445291",
+".S c #323E7C",
+".D c #439F36",
+".F c #404E8D",
+".G c #303C7A",
+".H c #3F4E8C",
+".J c #1F2A66",
+".K c #5F6AB2",
+".L c #2A3674",
+".P c #3A992D",
+".I c #283472",
+".U c #5560A8",
+".Y c #838CB4",
+".T c #327243",
+".R c #2D3F70",
+".E c #2D6148",
+".W c #49549C",
+".Q c #242E71",
+".! c #232E70",
+".~ c #171F57",
+".^ c #34457A",
+"./ c #348434",
+".( c #323C82",
+".) c #202A6D",
+"._ c #1F2A6C",
+".` c #424F8B",
+".' c #51619D",
+".] c #1D286A",
+".[ c #1C2669",
+".{ c #4F5F9B",
+".} c #2B367B",
+".| c #4B5B97",
+"X c #6E79C0",
+"X. c #283278",
+"XX c #273277",
+"Xo c #399332",
+"XO c #495995",
+"X+ c #253075",
+"X@ c #384581",
+"X# c #6A75BC",
+"X$ c #465592",
+"X% c #222C72",
+"X& c #455391",
+"X* c #212C71",
+"X= c #33417C",
+"X- c #202A70",
+"X; c #333F7C",
+"X: c #1D286D",
+"X> c #3F4D8B",
+"X, c #5A65AC",
+"X< c #364382",
+"X1 c #5761A9",
+"X2 c #344180",
+"X3 c #222D6B",
+"X4 c #323D7E",
+"X5 c #2C3978",
+"X6 c #3C478B",
+"X7 c #7D85AD",
+"X8 c #394588",
+"X9 c #388B37",
+"X0 c #767FA6",
+"Xq c #333F82",
+"Xw c #488654",
+"Xe c #424D94",
+"Xr c #1F296B",
+"Xt c #203062",
+"Xy c #3E4990",
+"Xu c #1D2769",
+"Xi c #2C377B",
+"Xp c #293578",
+"Xa c #293378",
+"Xs c #263175",
+"Xd c #495894",
+"Xf c #252F74",
+"Xg c #242F73",
+"Xh c #475692",
+"Xj c #343F86",
+"Xk c #222D71",
+"Xl c #747BA7",
+"Xz c #212B70",
+"Xx c #43528E",
+"Xc c #1F296E",
+"Xv c #1E296D",
+"Xb c #3E4C89",
+"Xn c #4D5C9B",
+"Xm c #3C4A87",
+"XM c #3A4885",
+/* pixels */
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.w ,Xa AX..N K y.O.$ v.u.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q W.S...f 3.* 0 q wXXX+ K PX%X* YX-Xc.7 e.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q E '.tX6.d.f 3.* 0.Q w.jXl K PX%X* Y.$.$XcXc 9 e.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q p $ $ _ '.tX6.d.g.(.* 0.Q.M.jXl y PX%X* Y.$.$XcXv 9 9 9.[ e.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.qX1X1.1 f _ '.tX6..Xj.(.*.v.Q.M.jXl y PX%Xz Y.$.&XcXv 9 9 9.=.x [.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q D.KX,.U.1 ( _ 'Xy.a..Xj.(.*.v.Q.M.jXl y PX%Xz Y.$XcXcXv 9 9 9.].x.x.[ e.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q s s.KX,.U $ ( =XeXy.a.fXj c n.v.mX..NXf y P.OXzX-.$XcXcXv 9 9 9.x.x.x B B.p.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.`X# s.KX,X1.1 $.W =.tXy.a.f 3 c 0 q wX. HXf PX%X*Xz.$.$XcXc 9 9 9.=.x.x B B B B [.~.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.qXdX X# s.KX,.U.1 ( _ '.tX6.d.f 3.* 0 q zXX.j.# PX%X*Xz.$.&XcXv 9 9 9.].x.x B B BXu.[ [.~.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q {X X# s.KX,X1.U $.W =XeXy.a..Xj.(.*.v.m zXXXl.# PX%Xz Y.$.&XcXv 9 9 9.].x.x B B BXu.[.[ [.~.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.qXdX X# s s.KX,.U.1 ( _ '.tXy.a.f 3 c n q w z.NXl.# P.OXz.$.$XcXcXv 9 9.].x.x B B BXuXu.[.[ [.p.~.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.`X X# s s.KX,X1.1 $.W =XeXyX6...g 3.* 0 q w 6 HXl.#X%X*Xz.$.&XcXc 9 9 9 9 9.x.x B B BXuXu.[ [ [.p.~.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.qX#X# s s.KX,X1.1 $ ( _ '.tXy.a.fXj c n.v.m.MXXX+ K PX%X* Y.$.&XcXcXvXv 9.z.z.z 9 9 9 9.] BXuXu [ [.p.q.q.q.q.q.q.q",
+".q.q.q.q.q.q s s s.K.KX,X1.U $ ( _ 'XeXy.a...g 3.* 0 q wX. HXfXg P.OXz Y.$.$.$.$.$.$.$.$.$.).).).)._._Xr 9.].]XuXu.p.q.q.q.q.q.q",
+".q.q.q.q.q D s.K.KX,X,X1.1 $ (.W =XeXyX6.d.f 3 c n.v.m AXX ] K.#.l.O.+.+.+.+.+.+.+.+ 6 6 6 6 6 ] ] ] ].).).)Xr.y.y : e.q.q.q.q.q",
+".q.q.q.q.q.K.KX,X,X1.U.1 $ (.W =Xe.tX6.a.fXj.(.* 0 q wX. H.) y.#.l PXkXkXk z z.Q.Q.Q.Q.Q.Q.Q.!.! z z x x ] ].)._.y._ :.q.q.q.q.q",
+".q.q.q.qX1X,X,X1.U.U.1 $ ( _ =Xe.tXy.a...g 3 c 0 q.m AXX H.) y.#.#XgXgXgXgXgXgXgXfXf.X.XXg.Q.e.Q.eX3.eX3X3X3X3X3.J.J.J %.q.q.q.q",
+".q.q.q pX1.U.U.1.1 $ (.W _ 'Xe.tXy.a...g 3 c n.v.} wX. HX+ ]Xf 5Xl.X.X.X.XXsXsXsXsXsXs.X.X.w.w.e.e.e.h.h.h.hXtXtXtXtXt.J e.q.q.q",
+".q.q.q $.1.1 $ $ (.W _ = 'XeXyX6.a...g 3.(.* 0 q w SXX. H HXsXsXsXsXs. . . . < < < &.w.h ) ) G a.B.0.0.0 | | | |.0 a d.J.q.q.q",
+".q.q.q $ f ( (.W _ = 'Xe.tXyX6.a...g 3.(.* 0 q w AXXXXXXXX. . . XXXX S S } } }.s.s.I.I ) G.B.0.4.E b.T i o o./ o o b.E aXt.q.q.q",
+".q.q E _ _ _ = = 'Xe.tXyXy.a.d.f.g 3.(.* 0 q C AX.XXXXXX S x S.jX0 }XpXp }Xp.8.I ) G.B |.4 +.T.T.T o./././././ o o b.E.B.hXt.q.q",
+".q.q ' ' ' 'Xe.t.tXyXyX6.a...fXj 3 c.* 0 q.m A S S S S S }.! wX0X0 > > > > g g ) G | + iX9.P.PXoX9Xo.PXoXoX9././ o.T.E.B.hX3.q.q",
+".q W.t.t.tXyXyXyX6.a.a...f.g 3.( c n 0 q C A S SXaXa } w w.e CX0X0 >.i g g G.B | +.T.;X9.9X9.; i b + +.E.E.4.4 | |.0.B ).h *.J.q",
+".q.SX6X6X6.a.a.a.d...f.gXj 3 c.* 0.v q w A S SXa A w C C C *.iX0X0.iX5 V.R.0 + iXo.P.P.P.9.; b +.4.r.r.r G G.R ) ) ) ).I.I &.J.q",
+".q...d.d.....f.f.fXj 3 3 c.* n 0 q.} w AX. SXa A w C C C.}XiXiXiXiX5 V G.4 +.;.9.9X9.;.T + |.B.r.R.R.R.R V V V V V W W.L.8.8.I.q",
+".q.f.f.gXjXjXj 3 3.( c.* n 0.v q.m w SXXXX SXa w C C C.}XiXi N ;.3 V.r.4 i.9.D.P.9 i +.r.r.R.< O O.S.SX4X4.<.< ~ @ @ @.3 T W.8.q",
+".w 3 3.(.(.( c c.*.* n 0.v q.m w AX.XXXXXX S } C C C.}Xi N * ; `.C.r.4 i.9.9.9 i + |.r.r.^X=X= pX2 pX2 X.>.>.>.S O.< ~ @.3 T g.I",
+" ,.*.*.*.*.* n 0 0.v q q.m w AX.XX H. XXXX S w C C.}Xi N ;.w @.C j +.;Xo.P.9 i.4.r.^X= pX<X< Q QX<X<X< . .X2X2 X.> O.<.G @.3 T.L",
+"Xa 0 0 0.v.v.v q q.m w w.MX.XX H HX+ HXX S } w C.}Xi N N ;.h.R jXw iXo.9.; +.4.r.^ UX< Q Q hX8 Q Q Q Q QX<X< .X2 p.>.S O.G @ @ g",
+" A q.Q.Q.Q.Q.m w z z z 6XX H ].).) ] H. x.!.e *XiXi.w.w.w.h.rXw.DXo.D.; +.r.^.^ Q Q h E E E E h h h h h Q Q QX< p p X.S O.G @ T",
+"X. w w.M.M.MX.X.XXXX.N HX+Xf K y yXfXs. S w C.iXiXi ;.3.R.r.4 iXo.9.; +.r.rX@ r h h.6.6.6.6.6.6.6 E E E h h Q QX< .X2 X.S O.G @",
+".NXX.j.j.j.j.N H.jXlXlXl KXg.#.#.# 5Xs. .jX0X0X0Xi ;X0 ` jXw.;Xo.D.;Xw j.CX7 h E.Y.Y.Y - ^ ^.Y.Y.Y.Y R.6.Y.Y # # r Q #X7X7X7.< @",
+" KX+XlXlXlXlXfXf.#.#.#.# P P.l.l.#XlXsXXX0X0X0X0Xi T ` j jXwXo.9.9 + j jX7X7 l ^ - - k k.H.H k k k kXbXb.Y.Y.Y.Y h r # #X7X7.S.G",
+" y K K y y y y P P P PX%X%.O.O PXg.XXsXX } >.i.i @ V.r.4.;.9.D.9 i.r.^X@ E.6 ^ ^ ^.H.H.F.F.F.F.F.F.H.HX>Xb.- R EXM h r Q . p X.<",
+".O P P P P P PX%X%X%.OX*X*Xz.+XkXg.XXs SXpXp.i g.R.r.4 i.9.9.9Xw j.r V T @.< ^.H.S.SX;X;.,.,X;X;X;X;.F.H O O.<.GXm E T T g W p.S",
+".$X%X%X%X%X%.OX*X*XzXzXz Y Y.+XkXg.X. S } > g.R.r.4.;Xo.D.9 i j.CX@ @.6 ^.H.H.,.,.,.:.:.A.A.A.A.:.%.%.,.F.HX>Xb.-XmXMXM r . pX;",
+" vX*X*X*XzXzXzXzXz Y.$.$.$.$.+XkXgXgXs <.8 ) G.0 + i.9.9.9 +.4 jX0 h @ ^.H.F.,.,.:.A.AX&.Z.Z.ZX&X&X&.AXx.% 8.HX>Xb.- EXM r r .X;",
+".u Y Y Y Y YX-.$.$.$.$.&.&.$.+ z.Q.w &.I.I G.0 +.9Xo.P.9 i.4.^.C #.6.<.H.F.,.,.:.AX&.Z u u u u u uX$.ZX&.A.% 8.`X>Xb.- EXM rX@X=",
+".qX-.$.$.$.$XcXcXvXv 9 9 9Xr.)X3.e.h.h G.0.4.T.;XoX9.; +.r.r.^ r E.6 ^.H.,.,.:X&.Z u u.V t t t t t.V LX$ I.@.% 8 MX>.nXmXM rX@.q",
+".qXc.$.$.& 9XvXvXv.z v.].].y !X3.h G.B.4.T.;.P.P.P.; +.r.^ p h E ^ ^.H.,.,.:X&.Z u.V t F FXO XO t.VX$ I.@.% 8.cXb.-XmXMX@.q",
+".q.7Xc.z.y.J.2.2.2XtXtXt d d a a.0.4 b iX9X9Xo.; i.4.r.r U Q h.Y - ^.S.,.:.A.Z u.V F D D D D D FXO J LX$ I.k 8.`X>.nXmXM.G.q",
+".q eX:.].2Xt d d d d a a.0.4.E.T oX9.P.P.PXo.; +.4.r U p QX8 E.Y -.H.S.,.AX& u.V F F.| Z Z Z Z Z Z D F J LX$ 4Xx 8.cXbXmXMX=.q",
+".q.qXu.2 d a |.E.E.E.E.E b.T o././X9X9.; i +.4.B.R.RX= . Q h.6.Y k.HX;.:.A.Z u t F ZXnXn.b.b.b.bXn Z D F tXh I.k 8.`Xb.-XM.q.q",
+".q.q e d.0 b./XoXo.P.PXo./Xo.P.PXo./ o +.4.B.R V.<.>X2 QX8 E.6 - k.FX;.:X& u.V F.|XnXn.b.{.{.{.{.bXn Z DXO.oX$.@.%.`Xb.n.^.q.q",
+".q.q.q d.0.E o o./././ o.T.T.T b.E |.0.B G ) V @X4.>X< QX8 E.6 ^.H.F.,.A.Z u t D ZXn.b.{.'.'.'.'.{.b {.|XO.oXh IXx 8.c.n.q.q.q",
+".q.q.q d a | b.T.T.T b.E.E |.0.B G ) ).I.8X5 ; ~X4X2X< Q h E.6 ^.H.F.,.A.Z u t F D Z.b.{.'.' 7 7.'.'.{.b Z FXdXh IXx 8.cXm.q.q.q",
+".q.q.q.~ d d a a a a a a d d dXt.h.h.w.I gX5 ;.<X4Xq . QX8 E.6.Y k.FX;.A.Z u t F D Z.b.{.' 7 7 7 7.'.{.b Z FXdXh I.k 8.c 1.q.q.q",
+".q.q.q.q.7 % % % % % % /.u.y._ x.Q.w.sXp.i @ ;.<X4Xq . Q Q h.6.Y k.FX;.AX& u tXO D Z.b.{.' 7 7 7 7.'.{.b Z FXdXh IXx 8.n.q.q.q.q",
+".q.q.q.q.q.p.u.u /.u.u [Xu.y.) 6.! &.sXp.i @ ;.<X4X2 .X< Q h.6.Y k.FX;.:X& u t D Z.b.{.'.' 7 7 7.'.{ { Z FXdXh 4Xx.c.q.q.q.q.q",
+".q.q.q.q.q e B B B BXu B 9._ ] z.Q & <Xp.iX5 ;.<X4X2 .X< Q h E.Y k.HX;.%X&X$.VXO F ZXn.b.{.'.'.'.'.{.{ Z.|XO.oX$ 4Xx 1.q.q.q.q.q",
+".q.q.q.q.q.q.p BXuXuXuXu.]._ ] x.Q.w <.s >X5 @ ~X4.>X2X< Q h E RXb.H.F.%.A.Z L tXO D ZXn.b.{.{.{.{.{ { Z FXdXh 2.k m.q.q.q.q.q.q",
+".q.q.q.q.q.q.q [.[.[.[Xu BXr.) x.e.w <.8 >X5 @ ;X4.>X2 . Q h E.6XbX>.H.,XxX&X$.V J F D Z {.b.b.b { Z Z FXO.o 2 4 8.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.~ [.[.[.[Xu 9.) ].! * &.8Xp.i.3 ~ OX4X2 .X< Q h.Y.YXb O.F.%.A IX$ L J F D.| Z Z Z Z.| FXO.oXh I 8 1.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.~ [ [ [Xu.].) ].!.Q.w <.8.5.3 @.< O.>X2X< Q h.Y.Y.- O.H 8.%.@ IX$ L tXOXO F F F FXOXd.oXh I 8.^.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.~.p [ [.]Xr ] x.e.w &.8 >X5 @ ~ O.>X2 . Q Q #.Y R.<X>.H 8.%.@ IX$Xh.o.oXdXdXdXd.oXh 2 I 8.^.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.~.p [Xu.y ] x.e * &.8Xp.5.3 ~.<.S XX2X< Q #.Y E.GXbX>.` 8.%.k 4 IX$XhXhXhXhXhX$ 2 4 8.^.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.~.pXu.y._ ].! *.w.I.8 gX5 @ ~ O.> p pX< r hXMXm.-XbX> M 8 8Xx.k.@ I I I I 4 4.k 8 1.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.p :._ ] x.e.w &.8.L.5.3 @.< O.> p . Q r h EXm.-XbX>.c.` 8 8.%XxXx.kXxXxXx m.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q e :._ ].e *.w.I.8 g.5 @ ~.<.S XX2 # # r TXM E.-.nXbX>.c.`.` 8 8 8 8.c 1.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q : ]X3.e.w &.I.8 g.3 @.G O.S XX7 # Q TXMXM EXm.-.nXbXbXb.c.c.c.n.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.7.y.e *.w.I.8 W T.3 @.G O.SX7X7 . g r rXMXMXmXmXm.-.n.nXm 1.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.J.e &.I.8 W T.3 @.G OX7X7 p W . r r rXMXMXMXM.^.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.J.J.I.8 g T @ @.G.<.S X p p .X@X@X@.GX=.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.I.L g T @ @.G.<.SX;X;X=.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q"
+};
diff --git a/arts/builder/pics/Synth_AUTOPANNER.xpm b/arts/builder/pics/Synth_AUTOPANNER.xpm
new file mode 100644
index 00000000..89506f3b
--- /dev/null
+++ b/arts/builder/pics/Synth_AUTOPANNER.xpm
@@ -0,0 +1,292 @@
+/* XPM */
+static char * Synth_AUTOPANNER_xpm[] = {
+"64 64 225 2",
+" c None",
+". c #161E54",
+"+ c #B2821C",
+"@ c #465284",
+"# c #2E3A74",
+"$ c #D2B624",
+"% c #8A662C",
+"& c #32465C",
+"* c #5E6AB4",
+"= c #CE9E14",
+"- c #222E64",
+"; c #4E5E94",
+"> c #42528C",
+", c #364684",
+"' c #36324C",
+") c #424A7C",
+"! c #CE8A14",
+"~ c #2A3674",
+"{ c #32427C",
+"] c #FACE14",
+"^ c #F6A204",
+"/ c #4E568C",
+"( c #2A2E5C",
+"_ c #1A2664",
+": c #3E4E84",
+"< c #CA9614",
+"[ c #363A64",
+"} c #F6B60C",
+"| c #3A468C",
+"1 c #D2AA1C",
+"2 c #4A5A94",
+"3 c #22265C",
+"4 c #FAC20C",
+"5 c #AA7E24",
+"6 c #5A62AC",
+"7 c #4A529C",
+"8 c #2E3A7C",
+"9 c #2A3274",
+"0 c #AE922C",
+"a c #222E74",
+"b c #3E467C",
+"c c #424A94",
+"d c #324284",
+"e c #FEDA14",
+"f c #FABE0C",
+"g c #222A6C",
+"h c #52526C",
+"i c #6A76BC",
+"j c #DEA214",
+"k c #525EA4",
+"l c #F6B20C",
+"m c #4E569C",
+"n c #2A325C",
+"o c #D69A14",
+"p c #AE8A2C",
+"q c #46568C",
+"r c #DE920C",
+"s c #FEB604",
+"t c #222A54",
+"u c #BA8224",
+"v c #926E34",
+"w c #D2A61C",
+"x c #CE9214",
+"y c #D29614",
+"z c #B27A24",
+"A c #2E3E7C",
+"B c #222A64",
+"C c #B2861C",
+"D c #4A567C",
+"E c #6672BC",
+"F c #D69E14",
+"G c #26326C",
+"H c #46529C",
+"I c #3A4A7C",
+"J c #2A367C",
+"K c #3A4274",
+"L c #FED614",
+"M c #FEAA04",
+"N c #3A4A8C",
+"O c #D2B224",
+"P c #424E8C",
+"Q c #2A326C",
+"R c #162254",
+"S c #323E74",
+"T c #926A34",
+"U c #3E4674",
+"V c #666EB4",
+"W c #D2A21C",
+"X c #262E64",
+"Y c #4E629C",
+"Z c #46528C",
+"` c #424E7C",
+" . c #FED214",
+".. c #F6A604",
+"+. c #4E5A8C",
+"@. c #1E2A6C",
+"#. c #363E84",
+"$. c #F6BA0C",
+"%. c #DAAA1C",
+"&. c #FECA0C",
+"*. c #4A568C",
+"=. c #263274",
+"-. c #3E4A7C",
+";. c #3A428C",
+">. c #FEE21C",
+",. c #5662A4",
+"'. c #4E5A9C",
+"). c #262A54",
+"!. c #B27E24",
+"~. c #464E8C",
+"{. c #B6821C",
+"]. c #4A527C",
+"^. c #323A6C",
+"/. c #8E6A2C",
+"(. c #626EB4",
+"_. c #D29E14",
+":. c #3A467C",
+"<. c #32366C",
+"[. c #CE8E14",
+"}. c #2E366C",
+"|. c #364274",
+"1. c #FECE0C",
+"2. c #2A2E6C",
+"3. c #1E2664",
+"4. c #CE9A14",
+"5. c #3A3E64",
+"6. c #D2AE1C",
+"7. c #FEC60C",
+"8. c #5A66AC",
+"9. c #BA961C",
+"0. c #4E567C",
+"a. c #3A4674",
+"b. c #FEAE04",
+"c. c #DE9614",
+"d. c #6E7ABC",
+"e. c #DAA61C",
+"f. c #3A364C",
+"g. c #FEDE14",
+"h. c #FEBA04",
+"i. c #D29A14",
+"j. c #D69214",
+"k. c #FEB204",
+"l. c #1A2264",
+"m. c #363E74",
+"n. c #4A569C",
+"o. c #8E6624",
+"p. c #AE7E1C",
+"q. c #323A84",
+"r. c #364284",
+"s. c #2E325C",
+"t. c #323E7C",
+"u. c #3E4A8C",
+"v. c #1A225C",
+"w. c #42466C",
+"x. c #464E7C",
+"y. c #525A94",
+"z. c #525AA4",
+"A. c #B67E1C",
+"B. c #626AB4",
+"C. c #FAA204",
+"D. c #CE9614",
+"E. c #FAB60C",
+"F. c #3E468C",
+"G. c #FEC20C",
+"H. c #262E74",
+"I. c #FEBE0C",
+"J. c #565EA4",
+"K. c #966E34",
+"L. c #D29214",
+"M. c #262A64",
+"N. c #B6861C",
+"O. c #2E367C",
+"P. c #2E326C",
+"Q. c #52629C",
+"R. c #FAA604",
+"S. c #FABA0C",
+"T. c #D28E14",
+"U. c #5E66AC",
+"V. c #222E6C",
+"W. c #4E5E9C",
+"X. c #425294",
+"Y. c #4E5694",
+"Z. c #2A2E64",
+"`. c #3E4E8C",
+" + c #4A5A9C",
+".+ c #2E3A84",
+"++ c #2A327C",
+"@+ c #3E4684",
+"#+ c #222A74",
+"$+ c #2A3264",
+"%+ c #465694",
+"&+ c #222A5C",
+"*+ c #4A5684",
+"=+ c #3A4A84",
+"-+ c #3A427C",
+";+ c #424E94",
+">+ c #262E6C",
+",+ c #465294",
+"'+ c #4A5694",
+")+ c #26327C",
+"!+ c #3E4A84",
+"~+ c #5662AC",
+"{+ c #4E5AA4",
+"]+ c #262A5C",
+"^+ c #464E94",
+"/+ c #B68224",
+"(+ c #4A5284",
+"_+ c #323A74",
+":+ c #D29E1C",
+"<+ c #3A4684",
+"[+ c #2E3674",
+"}+ c #36427C",
+"|+ c #FECE14",
+"1+ c #1E266C",
+"2+ c #D2AE24",
+"3+ c #4E5684",
+"4+ c #6E7AC4",
+"5+ c #FEDE1C",
+"6+ c #FEBA0C",
+"7+ c #D29A1C",
+"8+ c #36428C",
+"9+ c #323E84",
+"0+ c #3E4A94",
+"a+ c #464E84",
+"b+ c #B67E24",
+" =.9 9 ++++=.H.a #+g @.3. ",
+" &+_+r.r.q..+8 J )+H.=.H.a a g a l.. . . ",
+" <.) 0+F.;.r.9+.+O.O.J )+=.H.#+a @.@.@.1+l.l.. . ",
+" _+'.n.%+;+c | 8+#.q..+8 J )+H.a a a #+a a #+@.@._ l.. . . . ",
+" y.J.k m 7 ;+0+| 8+d q.O.J J J ++=.H.a #+@.@.@.@.#+@.@.1+1+l.. . ",
+" Y.B.8.~+z.m H ;+c F.8+#.9+.+O.++=.=.H.a V.a #+#+#+1+@.@.1+@.1+@.l.. . . ",
+" (.(.* 6 J.{+n.^+c F.| 8+9+q..+O.++)+)+H.H.#+V.@.@.#+1+@.@.1+@.1+@.1+_ l.. . ",
+" P i E B.U.~+k {+n.H 0+N ;.#.q.A 8 J J 9 =.=.a a #+a #+@.#+1+1+@.1+@.1+1+1+1+l.. . . ",
+" K i E E * 8.~+z.m H ^+c F.| r.q..+8 J )+)+H.a H.a #+V.#+@.@.@.1+@.1+1+_ 1+1+_ 1+l.. . . ",
+" / d.E E * 8.6 k {+n.,+;+0+| 8+#.9+O.J ++++H.)+H.a g #+@.@.@.@.@.@.1+@.@.@.1+@.@.1+@.l.. . . ",
+" K E i V V * 8.k z.n.7 ;+0+F.;.8+9+9+.+O.~ ++H.H.a a V.#+a #+@.@.1+#+1+_ 3 @._ 1+@._ 1+_ l.. . . ",
+" x.d.i E V * 8.J.k '.n.H ;+u.| r.9+9+8 O.J ++=.=.=.H.a @.#+@.@.1+1+@._ 3.% < 5 3._ 1+1+@.1+1+l.. . . ",
+" V E V (.U.U.~+J.{+n.,+^+c 0+| 8+9+q.8 8 J J )+a a a a a @.@.#+@.#+@.@.@.t C $.9.& @._ 1+_ 1+_ l.. . ",
+" E E E (.* 8.~+k {+n.7 ^+`.u.;.8+#.q..+.+J J =.H.H.X Z.B @.M.B @.@.3.@.M.3.3 ' j 4 9.&+@.@.@.1+1+@.l.. . ",
+" ) V B.B.U.8.J.k z.m 7 ^+c F.| ;.r.#.q.O.J ++++=.=.>+p 1 w 1 W W W W _.W = = 4.F S.G.E.+ ]+@.a @.@.@.@._ l.. ",
+" B.* U.8.~+k k z.n.7 H ;+c N | r.#.9+8 8 J J =.)+a Z.1 L L . .1.&.&.&.7.7.G.G.G.G.I.G.l o.- g V.#+g g @.. . ",
+" Y.U.8.~+J.J.z.{+n.%+;+;+0+F.| ;.9+9+q.O.O.J ++=.H.H.X 1 L &.1 w w W W = _._._._.F f I.E.+ ]+a a V.a V.#+V.@._ . ",
+" #.6 ,.k z.k {+ +n.7 ^+;+0+0+| ;.9+#.8 8 8 J =.=.)+=.=.Q 1 .6.s.n X $+Z.$+$+$+$+X f.j S.+ ( G G =.=.>+a >+a g g v.. ",
+" ~.z.z.{+m n.7 H H ;+c 0+| ;.8+r.9+q..+J J J ++=.=.)+=.s.1 .w Z.9 =.=.9 =.)+=.=.n + l {.n 9 9 =.=.=.=.=.>+=.G V.g _ ",
+" {+n.n.m n.7 H ^+;+c 0+F.;.8+#.9+q..+O.O.++++=.9 ++=.++Q w .W }.=.~ ~ J J ~ J Q % D.p.n 9 ~ J 9 9 ~ 9 =.=.H.H.V.G v. ",
+" }.n.n.H H ,+;+;+0+0+F.;.| ;.#.q.A q.8 J J 9 ++)+=.=.=.~ P.w .W }.++J ~ ~ J ~ ~ ~ ~ }.}.~ J ~ ~ ~ ~ ~ ~ ~ ~ =.9 >+Q V._ ",
+" ^+;+;+;+c 0+c 0+F.| | r.#.9+9+9+.+8 J J 9 )+~ 9 )+++++9 }.w .w ~ # J J J O.O.8 8 [+# 8 8 8 8 8 8 J J ~ ~ ~ ~ ~ ~ =.- . ",
+" 3 0+c 0+u.F.N | | ;.r.8+#.9+9+q.O.J O.J ++~ )+)+9 ~ ~ J ~ }.w 1.W }.~ 8 8 8 8 8 8 A 8 8 8 8 8 8 8 # 8 8 O.~ ~ ~ ~ ~ 9 ~ G 3. ",
+" q.F.| F.| | ;.;.8+r.#.#.9+9+8 O.8 O.++9 ~ )+9 9 J )+J ++J <.w 1.w <.8 8 8 8 A q.t.q.9+A A 8 A A 8 A 8 8 8 8 8 J J ~ ~ Q X . ",
+" S ;.8+;.;.8+r.#.9+9+9+q.q.O.8 O.J J )+)+=.++J 9 J 9 J J 8 <.w &.W ^.8 A A q.A A A t.t.9+t.t.t.t.t.t.t.A t.8 _+8 [+~ J ~ 9 G ",
+" 8+9+#.9+9+#.9+9+9+q..+8 J 8 J ++J =.9 9 ++~ =.J J J 8 ~ J ^.W 1.W _+9+9+9+t.t.#.r.d #.}+r.#.9+d 9+9+t.t.A t.A 8 A 8 # ~ ~ 9 ",
+"H.9+9+q.9+q.q.q..+8 8 8 O.J J J )+++)+=.=.)+J ~ J ~ J 8 8 J ^.W 1.W ^.t.t.d r.9+t.#.d d d d }+r.}+}+d r.#.t.t.t.8 t.8 # # # # ~ ",
+"9 q..+.+.+8 8 8 O.J J J J ++++=.9 =.=.)+J ++9 )+J 8 J 8 8 q.^.W &.W m.9+d 9+d r., , r.r.;.<+, r.r.r.r.}+d }+r.}+{ t.t.t.8 # J ~ ",
+"=.O.8 O.J J J J O.++++J )+=.)+H.H.H.H.=.=.J ~ ++J 8 J 8 A 8 m.W &.W m.#.r.r., r.r.<+<+, , <+<+<+, <+, <+r.r.d #.t.t.t.A 8 _+# [+",
+"J J ++J J J ++J )+J =.$+~ Q s.Q Q $+Q $+}.Q }.}.}.}.^.^.^.m.[ w 7._.K , , , r.<+<+<+| <+<+<+| , <+<+<+, , , -+, }+r.t.t.t.A 8 # ",
+"9 J ++++++J ++9 =.)+Q 0 $ O O O O O 2+6.6.1 1 1 1 w w W W W e.4 7.= m.r.;.<+, , N =+N N N =+u.N N | <+<+<+, r., r.r.}+{ t.A 8 8 ",
+")+H.)+=.=.H.=.)+H.H.2.$ >.>.>.5+g.e e L L L L .|+ .|+1.1.&.&.7.7.:+K <+, , | u.| N u.u.u.u.N u.u.=+u.N =+N =+<+, , r.#.{ t.t.# ",
+"=.H.=.H.=.a H.H.H.a 2.0 O O O 6.2+2+2+1 1 1 w 1 w W w W W _.e.4 7.W K N N u.N N u.u.u.`.`.P `.`.`.`.: u.!+F.=+<+<+, , r.}+{ { t.",
+"a a a a a H.a a a H.g X X X X Z.Z.Z.$+P.P.}.^.<.^.^.^.S m.|.5.j G._.:.| @+N u.`.`.`.`.`.`.`.P `.P `.c `.u.: u.=+<+<+<+-+r.#.#.8 ",
+"a a a a a a a a V.a #+V.g #+#+V.=.H.=.=.++~ 8 J A 9+t.t.t.d |._.G.i.U N u.N u.u.`.P P ;+> > P ;+P > `.`.u.u.`.!+!+<+=+, , }+}+t.",
+"g #+#+#+#+#+V.a @.#+V.#+a V.V.a a =.=.J ~ J J 8 8 8 9+d r.r.K :+G.:+:.N N `.P > P X.X.> X.X.,+> X.P > > > : c `.N =+<+<+:.r.}+t.",
+"@.a V.a V.#+@.a @.@.@.@.@.@.#+V.a =.=.J ~ J 8 8 t.q.t.9+r.r.|.:+G.i.b `.`.`.`.X.> > ,+,+Z %+%+,+%+X.X.X.> > `.P u.N =+<+<+, , }+",
+"3.g #+@.#+g #+g #+#+#+@.@.#+V.#+H.H.=.=.J 8 8 8 8 t.9+r.r., -+_.G.:+-.`.P X.;+X.X.,+%+%+%+,+,+%+,+q ,+> ,+> > `.P : u.=+=+<+-+t.",
+" @.#+@.@.@.@.@.@.@.1+1+@.@.a a =.H.9 =.~ J 8 A A 9+{ r.r.<+K i.I.i.b `.`.> P ,+X.,+,+%+2 2 %+2 %+%+'+%+,+Z Z > P `.u.=+<+, <+ ",
+" @.@.@.@.#+1+@.@.@.#+#+1+#+g V.a =.~ J J 8 8 q.9+{ 9+d , , :._.G.7+) `.;+X.%+,+%+%+2 2 %+%+2 %+n.2 %+%+%+X.X.P P P : !+!+<+, ",
+" . 1+#+1+#+#+1+@.@.@.@.@.g a a H.H.=.9 J O.8 8 9+#.r.r.r.<+:.i.I.4.) > P X.%+%+%+%+%+ + + ++. +2 2 2 %+'+q %+Z > P `.`.!+<+S ",
+" v.@.@.@.@.1+@.1+1+1+1+1+@.g V.=.=.9 J ~ 8 8 t.t.{ r.r.| <+K i.I.i.) ;+,+Z %+%+2 + +2 W. +W.; '.'.2 2 2 %+q %+> > P !+!+a.X ",
+" l.@.1+@.1+@.@.@.@.@.@.@.#+a =.=.=.J J 8 8 8 9+t.r.r., N :.i.6+7+: > X.X.%+%+'+2 +*++.*+W.W.W.'.W.2 +%+%+,+X.P P `.=+<+ ",
+" v.1+@.1+@.1+1+1+1+1+@.#+V.V.a =.~ ~ # J 8 9+t.d d , ;.<+U 4.I.4.) > ,+%+%+n.2 2 *.T [.!.].; Y W. +2 2 '+%+q Z > > : `.n ",
+" l.@.1+@.@.@.@.@.1+@.@.#+H.a =.=.++# 8 8 A 9+r.r., <+| b i.h.i.) > ,+,+2 %+ ++.W.@ u ^ /+].Y Q.W.'.W.2 %+%+%+> P P : ",
+" _ _ @.1+1+_ _ _ 1+@.g V.V.=.=.++~ J 8 8 q.t.t.d r., =+a.D.h.o ) ` @ @ @ q *.*+*+(+h c.R.b+D W.Y ; 2 2 2 %+> X.> `.|. ",
+" . l.1+_ 1+1+1+@._ 1+g a V.a =.~ ~ ~ 8 A t.9+#.}+r.8+N b 7+h.k.o D.y L.L.L.x L.L.x y R.M C.u ].Y W.'.2 2 '+Z Z P P :. ",
+" 1+@.@.@.@.1+_ 1+@.@.@.H.H.=.=.)+J # 8 8 t.{ r., <+<+a.D.6+6+s s k.s k.k.k.b.b.b.M M M M ^ K.+.W.W.+.'+%+%+> > I ",
+" . 1+1+@.1+1+1+1+g @.V.G =.~ ~ J 8 8 t.9+{ r.r., <+:.5 D.y L.D.x L.L.L.L.x T.T.j.R.M ^ A.].; W. +2 2 q ,+Z : ",
+" _ 1+_ _ 1+@._ @.@.V.a a H.=.~ ~ [+8 8 t.9+r., ;.N <+b b -.` a+x.@ @ @ *+3+*+D h c.C.A.].k W.2 2 2 %+,+q > }. ",
+" l.1+@._ @.1+@.@.g V.=.=.=.~ J # 8 8 t.t.t., }+<+<+u.u.u.`.X.> Z '+%+%+ + +].A.^ A.].; Q.; W.2 '+%+Z > P ",
+" _ _ 1+_ 3.1+1+@.g V.H.=.9 ~ J 8 8 t.t.r.r., <+<+=+u.`.P P X.%+%+%+2 2 *+T ! z ].; W.2 W.2 2 2 q q > ",
+" . l.1+_ _ @.@.@.g V.H.=.~ ~ ~ 8 8 t.t.t.r.r., <+=+N !+`.P P X.,+%+'+%+%+@ @ *+'.; W.2 2 '+%+%+X.P a. ",
+" . _ 1+1+1+1+g V.a G =.=.~ J # 8 8 A 9+}+r.<+| =+!+`.`.`.> > q ,+%+%+'+2 2 +2 2 2 2 '+2 q q @ }. ",
+" . . 3.3.@.@.g #+V.=.=.~ J # 8 q.S t.{ d , ;.<+<+!+u.`.`.P > > %+q %+'+'+2 '+'+'+2 %+'+,+> a. ",
+" v._ _ 1+1+V.V.H.>+=.9 9 ~ # A A t.9+}+}+, , <+| : u.P `.P > Z ,+,+q q %+%+%+%+,+Z > > }. ",
+" . R @.1+@.V.a >+=.~ ~ J ~ 8 8 t.t.#.}+r., <+<+=+N `.`.P P > > X.X.Z q q q q %+Z > a. ",
+" l.@.g @.V.=.G =.=.~ O.[+8 t.t.{ { r.<+, | @+!+!+`.`.`.`.> > Z X.> X.> > > > ",
+" . @.@.g V.>+9 =.~ ~ # # 8 q.t.}+t.}+, , <+=+<+!+`.: c P `.> P P P P : :. ",
+" @.V.g a G G ~ ~ J J # A t.t.{ r.}+, , <+N <+!+!+: !+P !+`.P `.: ",
+" _ - a =.>+9 ~ [+8 # 8 A t.t.{ }+r.r.<+<+<+=+=+!+=+`.: : !+:. ",
+" @.G =.=.~ ~ ~ # # q.t.t.#.}+}+}+<+, <+<+=+!+<+}+ ",
+" &+- =.~ ~ O.# # q.A t.}+r.{ }+r.<+, S { ",
+" 9 ~ # # # _+8 A S #.}+}+ "};
diff --git a/arts/builder/pics/Synth_BUS_DOWNLINK.xpm b/arts/builder/pics/Synth_BUS_DOWNLINK.xpm
new file mode 100644
index 00000000..60596d77
--- /dev/null
+++ b/arts/builder/pics/Synth_BUS_DOWNLINK.xpm
@@ -0,0 +1,323 @@
+/* XPM */
+static char * BUS_DOWNLINK_xpm[] = {
+"64 64 256 2",
+" c None",
+". c #161E54",
+"+ c #828698",
+"@ c #35427C",
+"# c #8A4664",
+"$ c #F5C224",
+"% c #52629C",
+"& c #96162C",
+"* c #CA8419",
+"= c #5C4644",
+"- c #612244",
+"; c #43528C",
+"> c #28326C",
+", c #C6A254",
+"' c #3A3658",
+") c #E0E2E4",
+"! c #A0A2B4",
+"~ c #52424C",
+"{ c #303A73",
+"] c #8E6644",
+"^ c #3C4A84",
+"/ c #EC920C",
+"( c #BEBEC9",
+"_ c #525A7C",
+": c #6D7294",
+"< c #EEA20C",
+"[ c #ECB624",
+"} c #BEC2CC",
+"| c #B68234",
+"1 c #D70A14",
+"2 c #9E6624",
+"3 c #D1D2D6",
+"4 c #565A7C",
+"5 c #62668C",
+"6 c #343267",
+"7 c #3E4274",
+"8 c #BE9644",
+"9 c #741E3C",
+"0 c #B0B2C0",
+"a c #4E2C54",
+"b c #515677",
+"c c #F1F2F4",
+"d c #F5AA16",
+"e c #9396A5",
+"f c #2E3A7D",
+"g c #202A6D",
+"h c #273276",
+"i c #EA1214",
+"j c #A27A4C",
+"k c #364285",
+"l c #3E4A8E",
+"m c #F69604",
+"n c #DADADD",
+"o c #5662AB",
+"p c #455295",
+"q c #3C366A",
+"r c #4B5A97",
+"s c #EB060C",
+"t c #CD8A1D",
+"u c #6F4E37",
+"v c #464A7C",
+"w c #B8BAC4",
+"x c #7A5A4C",
+"y c #552E54",
+"z c #F6BA24",
+"A c #C7CAD3",
+"B c #565A8C",
+"C c #525AA1",
+"D c #868AA4",
+"E c #AE2C40",
+"F c #E9EAEC",
+"G c #F8A208",
+"H c #262E73",
+"I c #363A6B",
+"J c #7A7EA4",
+"K c #EA9A14",
+"L c #6672BC",
+"M c #BA923C",
+"N c #6A6E97",
+"O c #841E38",
+"P c #B6B6C5",
+"Q c #FAFAFC",
+"R c #FBAA04",
+"S c #363E82",
+"T c #B57E35",
+"U c #866284",
+"V c #AE0E1C",
+"W c #2E3264",
+"X c #A6AABC",
+"Y c #966634",
+"Z c #C29A4C",
+"` c #9A9EAD",
+" . c #222E71",
+".. c #2E367A",
+"+. c #3A4586",
+"@. c #424E8E",
+"#. c #5E6AB4",
+"$. c #4A5597",
+"%. c #3B3E6C",
+"&. c #EE0E14",
+"*. c #464E92",
+"=. c #1E266B",
+"-. c #7C82A4",
+";. c #D68611",
+">. c #682644",
+",. c #B98A41",
+"'. c #AE6E1C",
+"). c #D6D6DE",
+"!. c #722644",
+"~. c #B2B6C0",
+"{. c #323E7E",
+"]. c #DEDEE1",
+"^. c #5A62AC",
+"/. c #F70204",
+"(. c #8A5E34",
+"_. c #CECED5",
+":. c #FEA304",
+"<. c #3A4279",
+"[. c #664E44",
+"}. c #424A7C",
+"|. c #FEB204",
+"1. c #323666",
+"2. c #3E468A",
+"3. c #7A203A",
+"4. c #4E569B",
+"5. c #F6F6F7",
+"6. c #9A9AAC",
+"7. c #2A3678",
+"8. c #4E5E9C",
+"9. c #9E9EAC",
+"0. c #7A5234",
+"a. c #464E6C",
+"b. c #764E74",
+"c. c #6A5684",
+"d. c #66565C",
+"e. c #CE9224",
+"f. c #4A3E48",
+"g. c #A21224",
+"h. c #D29A28",
+"i. c #926E44",
+"j. c #965A7C",
+"k. c #DA8E14",
+"l. c #662A44",
+"m. c #E2060C",
+"n. c #BE0E1C",
+"o. c #5E6A9C",
+"p. c #747A9C",
+"q. c #866E54",
+"r. c #865A30",
+"s. c #BE7A1C",
+"t. c #926A4C",
+"u. c #A66E2C",
+"v. c #585E7C",
+"w. c #FA9E07",
+"x. c #6E7AC0",
+"y. c #EA1A24",
+"z. c #626AB4",
+"A. c #5D6284",
+"B. c #636EB4",
+"C. c #3E3E5C",
+"D. c #4A4668",
+"E. c #B28E5C",
+"F. c #654A39",
+"G. c #AE7C3C",
+"H. c #F29A07",
+"I. c #FEC214",
+"J. c #565EA4",
+"K. c #6A1E3C",
+"L. c #463A64",
+"M. c #8E6244",
+"N. c #F6B21C",
+"O. c #4A5281",
+"P. c #F2A214",
+"Q. c #FEBD14",
+"R. c #D2821C",
+"S. c #E6E6E9",
+"T. c #A6A6BC",
+"U. c #C6C6D2",
+"V. c #5E5674",
+"W. c #F20204",
+"X. c #EEEEF1",
+"Y. c #B61224",
+"Z. c #AEAEC4",
+"`. c #8285AC",
+" + c #B6721C",
+".+ c #FE0204",
+"++ c #C20E1C",
+"@+ c #FEB614",
+"#+ c #727694",
+"$+ c #A66A24",
+"%+ c #E6060C",
+"&+ c #19225C",
+"*+ c #EAA61C",
+"=+ c #656A91",
+"-+ c #A67E3C",
+";+ c #474E81",
+">+ c #F7BE1F",
+",+ c #CACED8",
+"'+ c #9A6A34",
+")+ c #525E8C",
+"!+ c #525EA3",
+"~+ c #868EAC",
+"{+ c #363E6D",
+"]+ c #2E3666",
+"^+ c #3A467C",
+"/+ c #BE7E2C",
+"(+ c #F29E10",
+"_+ c #921A34",
+":+ c #A2A6B5",
+"<+ c #323E74",
+"[+ c #3E4E84",
+"}+ c #B8863C",
+"|+ c #D2D6DC",
+"1+ c #414679",
+"2+ c #F2F6F4",
+"3+ c #F6AE14",
+"4+ c #969AAA",
+"5+ c #EE161C",
+"6+ c #364684",
+"7+ c #3E4E8C",
+"8+ c #DADEDE",
+"9+ c #5366A4",
+"0+ c #465694",
+"a+ c #3A3A64",
+"b+ c #CE8E1C",
+"c+ c #72523C",
+"d+ c #7E5E44",
+"e+ c #585E86",
+"f+ c #EAEEF0",
+"g+ c #F9A606",
+"h+ c #FDAE08",
+"i+ c #AF7224",
+"j+ c #F6060C",
+"k+ c #72527C",
+"l+ c #BA1224",
+"m+ c #662240",
+"n+ c #FAB614",
+"o+ c #46568C",
+"p+ c #2A366C",
+"q+ c #EE960C",
+"r+ c #C2C6CC",
+"s+ c #76223C",
+"t+ c #FA9A04",
+"u+ c #BABEC4",
+"v+ c #E69E14",
+"w+ c #6A76BC",
+"x+ c #FEFEFC",
+"y+ c #AAAEBC",
+"z+ c #C49E4C",
+"A+ c #7E86A4",
+"B+ c #5B66AC",
+"C+ c #D29624",
+"D+ c #DE0A0C",
+"E+ c #423E74",
+"F+ c #DE860C",
+"G+ c #925E2C",
+" &+h h h h h H .g g g =. ",
+" =.H ..{.S f f ..h H h H H .=.. . . . . ",
+" > <.1++.k k S f ....7.h h .g .g g =.=.&+. . . ",
+" W *.4.p *.l l k S f f f 7.h H .H H g .g g g g =.. . . . . ",
+" v !+C 4.p @.l 2.k k f ..7.7.7.h h . .g g .g g g =.=.&+&+&+. . ",
+" ;+B+B+J.!+4.$.*.2.2.k S S f ..h h h .H . . .g g =.g g g g g =.. . . . ",
+" J.o.#.B+!+C $.*.*.l 2.k S f f ..h h h .H g g g g g =.g g =.=.g =.=.&+&+. . ",
+" 7 L B.B.B+o !+4.$.p l 2.k S f S f 7.7.h h h . . .g g g g g =.g g =.=.=.g =.. . . . ",
+" 7 w+w+B.z.^.J.!+4.p *.l 2.6+k f f f ..h h H H H g .g g g =.g =.=.g g =.=.=.=.=.&+. . . ",
+" 4.x.L B.B.#.o !+4.4.*.7+l 2.k S S ..7.h h H h . . .g g g g g g g g =.=.=.=.=.=.=.g &+. . . ",
+" 7 : w+L z.B+B+o !+4.0+*.l 2.k k S {.f ....h H H . . . . .g g =.g =.g g g &+g =.=.=.=.=.&+. . . ",
+" @.x.w+L B.z.B+o C 4.4.*.7+l 2.k S S f ..7.h h h H H g g g g g g g =.g &+=.=.g =.g =.=.=.=.=.&+. . . ",
+" B+w+B.B.#.B+o !+C 0+p *.l 2.2.k {.f f f 7.7.h h .H .g g g g g g g g g g g =.&+g g g =.=.=.=.&+. . ",
+" B.B.B.B.z.B+o !+C 4.$.p l l 2.k S f f f 7.7.h . . . .g .g g g g g g g g g g . .g g g g g =.=.g . . . ",
+" 1+z.z.z.B+o o !+C r p *.*.l 2.k k S f ....h h h h H . .g . .g g g g .g .g g g .g g .g .g g g =.=.. . ",
+" #.#.B+o J.!+C 4.4.*.*.l l k k S S {.f 7.h h H h g . .g .g g . . . .g .g . . .g . .g .g g g =.g =.. . ",
+" v % B+o.`.~+D `.-.-.J J #+#+: : =+o.5 5 5 A.A.e+e+4 B 4 b b 4.b o+b o+_ o+b o+b o+_ O.b O.b b O.b b b a.g g =.. ",
+" S ^.J.C J F c c c c c c X.f+F X.F X.F F F S.S.) ].].].n n n n n ).).|+|+3 |+3 3 3 3 ,+3 3 3 3 ,+3 ,+,+,+y+{+g &+. . ",
+" }.J.C 4.J X.Q x+x+Q Q Q Q x+Q x+Q Q x+Q Q x+Q Q 5.5.c c c X.f+X.X.F F F F F F S.S.S.F F ) S.) S.) S.) ) r+}. . .g =. ",
+" $.4.$.$.N A |+3 3 3 3 3 _.,+,+A A A U.U.U.} r+} } ( ( u+w w w w w w ~.w ~.~.~.~.~.~.0 0 ~.~.~.0 ~.0 0 0 :+b > H =.. ",
+" W @.$.p p *.*.O.*.;+v 1+1+7 7 S %.I I I { 1.6 6 W ]+]+W W h W ]+W 6 1.]+]+1.1.1.]+W ]+1.]+]+]+]+W W 1.]+W > > > > . .. ",
+" *.*.*.*.l V.E.z+, z+z+z+Z Z 8 ,.d.D.j ,.,.,.,.,.}+}+| | x a+t.T | | | T T | T G.] I d+G.T T T T T T G.s.'+W > > > > g . ",
+" &++.l l l 2.v t.[ $ $ $ $ >+z z N.T M.-+*+3+3+3+3+d d *+g+* u u ;.K P.g+< < G G (+k.u F. +q+w.G G (+w.(+(+/ u W p+p+> > H &+ ",
+" f l 2.k 2.+.k v E.$ I.I.I.Q.Q.Q.n+3+C+t.$+v+|.|.h+h+h+h+g+G R.~ r.;.H.:.g+:.g+G G m ;.= u +t+:.w.:.:.:.w.m F+F.W h 7.> .. ",
+" > k 2.k k k S 7 q.[ >+Q.Q.Q.z n+n+3+v+Y ~ ;.3+h+R R R R R G H.G+f.$+H.:.:.:.g+:.G G t+2 = 0./ :.w.w.w.w.w.w.m '.f.]+f p+> H ",
+" S k S S S S S %.-+h.h.C+h.e.e.e.e.t (.' '+t t b+t t * t * * 2 ' r.s.* * * * R.* * * '.C.F.i+s.* * R.R.* * s. +f.]+f 7.]+> &+ ",
+"=...{.f S f f f I I I {+I I I ' ]+]+> > H W 1.]+1.1.I I { 1.6 6 1.1.I {+{+I {+I {+{+{+{+<+<+7 {+a+{+{+a+I {+a+I { f {.f f { p+g ",
+"h f f f f f ..;+T.P P ~.0 ~.0 0 0 0 0 0 0 0 y+Z.y+y+X ` B b.E Y.Y.E c.=+! X :+X :+T.X :+:+X :+:+:+:+:+:+:+:+:+4+_ {.{ <+f { p+..",
+"7...f ........e+) 2+c 5.c 5.2+c X.X.c X.X.X.F f+F F S.n N j.5+j+j+y.U -.|+) ].) ].].].].n ].].) 8+8+8+8+n n n A _ {.{.{.f { { 7.",
+"h h ..7.7.7.h B n c 5.5.5.2+5.c c c X.c X.X.X.F X.F S.A B # &././.i b.: _.) ) ].].].].8+].n ].n n n n n n n n u+a.{.{.{.{.{.{.{ ",
+"h h h h h h H 1+e ! ! ! 9.9.! 9.9.` ` ` ` ` 9.6.` ` ` + I >.s .+/.m.y v D 4+6.4+4+4+4+4+4+4+4+4+4+4+4+e e e e -.^+@ @ @ {.{.f { ",
+"h h h h h h h h H h h H h H H H H > > > > > 7.{ 7.{ { {.{ - W..+.+m.a {+<.@ ^+^+^+6+1+^+1+^+1+^+1+^+^+^+6+^+@ <.@ @ @ {.@ {.{.f ",
+"H H H H . . .h H .H H . . . . .H h h 7.7.7.f 7.f f {.f - %+.+.+m.a k ^ +.^ ^ l ^ 7+7+7+7+7+7+l ^ 7+[+^ ^ ^ 6+6+6+6+@ @ @ @ {.",
+" . .h .H H H . .g . . .g . .H h H h h 7.7.7.f f {.{.{ - W..+.+m.a 6++.7+l l 7+7+7+7+7+7+@.7+7+@.7+l l ^ ^ ^ +.+.6+k k {.{.f ",
+" .g . . . .g .H .g g .g g g .h h 7.h 7.f f f f f {.{ - %+/..+m.a +.^ 7+7+7+@.@.@.@.; ; @.; ; 7+; 7+@.7+l 7+^ 2.^ 6+6+@ @ {.",
+"g . . .g g H . .g g g g g . . . .h h 7.7.7.f f {.{.{.{.- %+.+/.m.a ^ ^ l 7+@.; 7+p p p p ; p ; p 7+; @.7+7+^ ^ ^ +.6+^+k @ {.",
+"g g g .g g g g g . .g g g . .h .h 7.7.f f f {.{.k {.{.- W..+/.m.a ^ 7+7+7+7+p ; ; p ; 0+p p ; 0+p ; @.; ; 7+^ [+^ +.+.+.6+@ ",
+"=.g g g .g g g g g g g g g g H .h h h 7.7.7.{.f {.{.k {.- %+.+.+m.a +.7+@.p p p p 0+0+0+p 0+0+0+; p ; p @.@.@.7+l ^ ^ ^ 6+<.{.",
+" . g g g g g g g g g g g g g .H h h h 7.f 7.f {.f { S {.- %+.+/.m.y ^ 7+l @.; 0+p p 0+r 0+0+$.r 0+0+0+o+p ; ; 7+7+[+^ ^ 6+^+ ",
+" g g g g g g g =.=.g g =.g . .h H 7.7...7.f {.f 1.9 { <+- W..+.+1 y ^ E+s+[+0+p 0+r r 0+r r r 0+r r 0+0+o+p @.; @.l ^ 2.@ > ",
+" . &+g =.=.g g g =.=.g g g g .h .h 7.f f f f f 6 n.K.1.m+%+.+.+D+y L.s+Y.}.0+0+0+0+r r r r r r r r 0+0+0+0+; @.; 7+[+^ ^ { ",
+" &+g g g g =.g g g g =.g g . . .h 7.h 7.f f {...6 1 1 K.& W..+.+W.O 3.D+++v 0+r r r r r r r 8.r r r r 0+o+0+; ; @.7+^ ^ @ H ",
+" . =.g g =.=.=.=.g =.=.g g H h H 7.7.7.7.f {.{ 6 g.W.%+W././..+/.W.W.%+_+@.0+0+r r 8.8.8.8.8.8.8.r r r 0+$.o+; ; ; @.^ ^ ",
+" &+g =.=.g g g g =.g g g . . .h h h 7.f f {.{.{.6 V /./..+.+.+/.W.%+_+}.p 0+r r 8.8.8.8.8.8.8.8.8.8.r $.0+0+; @.@.[+}.H ",
+" . g =.=.=.=.g =.=.=.g g .h h 7.7.7.f f {.{.k k 1.& %+/./..+W.1 3.1+o+r 0+r r r 8.% 8.% % 8.% 8.r 8.r o+0+o+; @.[+^ ",
+" =.=.g =.g g =.=.g g g . . .h h 7.f f f f {.{.k @ q 9 m././.1 >.1+; 0+0+r r 8.8.8.8.% % % % 8.8.8.r r $.0+p ; ; 1+p+ ",
+" . &+g =.&+g &+=.=.=.g . . .h h h 7.f {.f {.{.k k <.' 9 m.m.>.E+@.p 0+0+r r 8.8.8.% 9+9+9+9+% % 8.8.8.r o+p ; ; 7+^+ ",
+" &+=.=.g =.g g g g g g H h h h 7.7.f f {.{.k k k k <.q 3.s+7 7+; ; p r r r r 8.% % % % 9+% % 8.)+r r 0+0+o+; 7+I ",
+" . =.&+g &+=.=.=.g .g .h h 7.7.f f {.{.@ k k k +.+.<.1+l @.p o+p 0+0+r 8.8.8.% % % 9+% % % 8.r r r o+p ; [+ ",
+" &+=.g =.g =.=.g g g .> > p+7.7.7.f f {.{.@ 6++.+.^ ^ l 7+; ; p 0+0+r r r r 8.8.% % % % % 8.8.r r 0+0+; [+W ",
+" . &+=.=.=.=.g g g g . .h 7.7.f f { {.k {.6+6+6+^ ^ 7+l 7+; ; 0+0+0+r r 8.8.8.8.8.% 8.8.8.8.r r o+o+; ; ",
+" =.&+=.=.=.=.g . . .h > h p+7.f f {.{.@ k 6++.6+^ ^ 7+@.7+p ; p 0+0+r r r 8.8.8.8.8.8.r r r 0+; o+@ ",
+" . &+=.&+=.=.=.g . . .h 7.7.7.f f {.{.{.k k +.6+^ ^ l 7+7+p ; 0+o+0+0+r r 8.8.r r r r r o+o+$.; ; @ ",
+" . g g &+=.g g g .> > h p+7.f f f {.{.{.k 6++.+.^ 7+7+@.7+; ; p o+0+0+0+o+r r r r r o+r o+o+O.]+ ",
+" . &+&+=.g g g g .h h 7.7.f f { {.@ k k 6+6+6++.l [+7+7+; ; p o+o+o+r o+r r r o+r o+$.o+; @ ",
+" &+g &+=.g g .H .> > > p+f {.{.{.{.@ k 6++.^ +.^ ^ 7+7+; ; p p 0+; 0+o+o+o+r ; o+o+@.]+ ",
+" . &+=.g g . . .h 7.7.7.7.f f {.{.k k 6+k ^ ^ l l l l 7+@.; ; p ; ; ; ; ; o+p ; ; ^+ ",
+" =.g g g . .> > h p+7.7.f {.{.{.@ @ 6+k 6+^ ^ [+[+[+7+7+7+; ; ; p ; p ; ; @ ",
+" . =.g . . .> h 7.7.{ f f <+{.{.@ k k k +.+.^ l [+[+@.7+@.@.; ; ; @.[+1+ ",
+" g g g .h > p+7.p+7.f f {.{.{.@ ^+6+6+^ +.+.^ l ^ 7+[+[+7+7+[+@ ",
+" . g .> .h h 7.f { f {.{.{.{.@ 6+k 6+^ +.^ ^ ^ l ^ ^ ^ ^ ^+ ",
+" g > > p+p+p+f { f <+{.{.S S @ @ k ^++.+.+.^ ^ ]+ ",
+" . .> h 7.f f <+<+{.@ @ @ @ k 6+^+^+<+@ ",
+" > p+7.7.f { { f {.@ @ > "};
diff --git a/arts/builder/pics/Synth_BUS_UPLINK.xpm b/arts/builder/pics/Synth_BUS_UPLINK.xpm
new file mode 100644
index 00000000..3c4b45ca
--- /dev/null
+++ b/arts/builder/pics/Synth_BUS_UPLINK.xpm
@@ -0,0 +1,323 @@
+/* XPM */
+static char * BUS_UPLINK_xpm[] = {
+"64 64 256 2",
+" c None",
+". c #161E54",
+"+ c #727A8C",
+"@ c #8E162C",
+"# c #3A4A7C",
+"$ c #561A3C",
+"% c #2E3668",
+"& c #B5B6BC",
+"* c #52629C",
+"= c #6C4A34",
+"- c #C27A19",
+"; c #525274",
+"> c #3E364C",
+", c #3E1E4C",
+"' c #4A567C",
+") c #8E5664",
+"! c #35427C",
+"~ c #F29604",
+"{ c #1E2A64",
+"] c #3A4A86",
+"^ c #D00A14",
+"/ c #3A366C",
+"( c #D2D6D4",
+"_ c #2A2E5C",
+": c #8E92A4",
+"< c #DE860C",
+"[ c #4E3A3C",
+"} c #8A623C",
+"| c #464E8C",
+"1 c #DE1A24",
+"2 c #323E7C",
+"3 c #EE464C",
+"4 c #6E728C",
+"5 c #9D6A2C",
+"6 c #ED060C",
+"7 c #DA9A9C",
+"8 c #464A6C",
+"9 c #263273",
+"0 c #2B367C",
+"a c #C4C6CC",
+"b c #4E5E9A",
+"c c #F9A204",
+"d c #6C1E3C",
+"e c #6A564C",
+"f c #D28612",
+"g c #322A5C",
+"h c #364285",
+"i c #E6E6E7",
+"j c #82869C",
+"k c #3E426C",
+"l c #475695",
+"m c #202A6D",
+"n c #42528C",
+"o c #9A9EAC",
+"p c #383E71",
+"q c #EE8E0C",
+"r c #AA6A1C",
+"s c #F90204",
+"t c #232659",
+"u c #AE1224",
+"v c #5F1A3C",
+"w c #5662AB",
+"x c #424A94",
+"y c #2A3279",
+"z c #525A94",
+"A c #FC9A04",
+"B c #9A96A4",
+"C c #6E7AC0",
+"D c #323665",
+"E c #DEDEDD",
+"F c #2C3260",
+"G c #49527C",
+"H c #3E468B",
+"I c #4E569B",
+"J c #1D2664",
+"K c #BBBEC4",
+"L c #D18214",
+"M c #82562C",
+"N c #B37221",
+"O c #5E66AC",
+"P c #7B8294",
+"Q c #A21224",
+"R c #424A73",
+"S c #451E4C",
+"T c #3A426F",
+"U c #3E4E8B",
+"V c #969AA8",
+"W c #E58E0C",
+"X c #6A4634",
+"Y c #464E94",
+"Z c #636EB4",
+"` c #CECED4",
+" . c #4A2A54",
+".. c #3A428C",
+"+. c #484660",
+"@. c #262E72",
+"#. c #363E83",
+"$. c #70523C",
+"%. c #8E6234",
+"&. c #F69E04",
+"*. c #262A5C",
+"=. c #E3060C",
+"-. c #EF0A0C",
+";. c #464E77",
+">. c #323A84",
+",. c #DA8A0C",
+"'. c #FA0A0C",
+"). c #661A3C",
+"!. c #525E99",
+"~. c #2B326C",
+"{. c #7A7E94",
+"]. c #4E264C",
+"^. c #2E3A74",
+"/. c #BABAC4",
+"(. c #CA8214",
+"_. c #F69604",
+":. c #3E4A94",
+"<. c #373A67",
+"[. c #9696AA",
+"}. c #58423C",
+"|. c #FEAA04",
+"1. c #D28A0C",
+"2. c #EEEEED",
+"3. c #3F4672",
+"4. c #222E71",
+"5. c #F69204",
+"6. c #FE0204",
+"7. c #5E1E3D",
+"8. c #5A62AC",
+"9. c #72768C",
+"0. c #BE1E2C",
+"a. c #EE2E34",
+"b. c #C60A14",
+"c. c #821634",
+"d. c #7E3E54",
+"e. c #5E4A4C",
+"f. c #9B662C",
+"g. c #323254",
+"h. c #D6C6CC",
+"i. c #32265C",
+"j. c #7E5E3C",
+"k. c #423E5C",
+"l. c #8E8EA0",
+"m. c #A6A6B4",
+"n. c #626684",
+"o. c #423244",
+"p. c #961E34",
+"q. c #6A76BC",
+"r. c #4A264C",
+"s. c #625254",
+"t. c #EA9A9C",
+"u. c #582244",
+"v. c #764E34",
+"w. c #3E2E5C",
+"x. c #745640",
+"y. c #4E4A5C",
+"z. c #5E463C",
+"A. c #A46A28",
+"B. c #8A5E34",
+"C. c #D70A14",
+"D. c #3E3A64",
+"E. c #DADADC",
+"F. c #F20204",
+"G. c #B26E1C",
+"H. c #B60E1C",
+"I. c #E2DEE4",
+"J. c #865A2C",
+"K. c #E68A0C",
+"L. c #FEA204",
+"M. c #A61224",
+"N. c #4A224C",
+"O. c #EA8E0C",
+"P. c #19225B",
+"Q. c #56464C",
+"R. c #4E567C",
+"S. c #424E8C",
+"T. c #4E5A9A",
+"U. c #424E78",
+"V. c #3A467C",
+"W. c #36326C",
+"X. c #46325C",
+"Y. c #767E94",
+"Z. c #B6BAC3",
+"`. c #222E64",
+" + c #2E3A7D",
+".+ c #364684",
+"++ c #EAEAEC",
+"@+ c #4A5A94",
+"#+ c #EF9207",
+"$+ c #AE6E1E",
+"%+ c #F6060C",
+"&+ c #5266A4",
+"*+ c #9A9AAB",
+"=+ c #7E5A34",
+"-+ c #B67624",
+";+ c #5F6AB4",
+">+ c #475299",
+",+ c #6672BC",
+"'+ c #6E4E34",
+")+ c #36467C",
+"!+ c #F09A04",
+"~+ c #9296A4",
+"{+ c #6E768C",
+"]+ c #4A4E6C",
+"^+ c #868A9C",
+"/+ c #9EA2AC",
+"(+ c #FE9E04",
+"_+ c #BEC2C4",
+":+ c #9E1624",
+"<+ c #46224C",
+"[+ c #E6920C",
+"}+ c #D1D2D4",
+"|+ c #CA7A14",
+"1+ c #2A265C",
+"2+ c #4E5274",
+"3+ c #96622C",
+"4+ c #A26624",
+"5+ c #561E44",
+"6+ c #46528B",
+"7+ c #323A69",
+"8+ c #3A4686",
+"9+ c #262E64",
+"0+ c #5E4E54",
+"a+ c #96162C",
+"b+ c #D68214",
+"c+ c #52669C",
+"d+ c #F69A04",
+"e+ c #FE0604",
+"f+ c #5A66AC",
+"g+ c #D6CACC",
+"h+ c #F20604",
+"i+ c #E2E2E4",
+"j+ c #FEA604",
+"k+ c #A61624",
+"l+ c #EA920C",
+"m+ c #2A3674",
+"n+ c #47568C",
+"o+ c #2A2E6C",
+"p+ c #323E84",
+"q+ c #1E266C",
+"r+ c #535EA4",
+"s+ c #363A74",
+"t+ c #3E3E6C",
+"u+ c #1A2264",
+"v+ c #26327C",
+"w+ c #525AA4",
+"x+ c #3A427C",
+"y+ c #424E94",
+"z+ c #4E5AA4",
+"A+ c #767A92",
+"B+ c #3E4A77",
+"C+ c #C67A1C",
+"D+ c #222A62",
+"E+ c #3E4A87",
+"F+ c #D6D6DA",
+"G+ c #2E2E64",
+" u+y y y y 9 @.4.m m m J ",
+" t _ m+2 #. + +0 v+@.v+@.@.4.J . . . . . ",
+" F x+8+H ..h p+ +0 0 0 v+v+4.m 4.m m q+q+u+. . . ",
+" F | l >+y+:.H h p+>. + +0 v+@.4.@.@.m 4.m m m m q+. . . . . ",
+" x !.w+I >+Y :.H ..h >.0 0 0 0 v+v+4.4.m m 4.m m m q+q+u+u+u+. . ",
+" ;.O O r+r+I >+x :.8+h p+p+>.0 y v+v+4.@.@.4.4.m m q+m m m m m q+. . . . ",
+" !.;+;+f+r+z+I >+y+:.8+..p+>.>.0 y y v+@.4.m m m m m q+m { q+q+m J q+u+u+. . ",
+" k ,+Z Z O 8.r+z+>+>+x H ..#.>.p+ +0 0 v+v+v+4.@.4.m m m m m q+{ { q+q+q+{ q+. . . . ",
+" k q.q.Z ;+8.r+w+z+>+y+:.8+.+.. + + +0 y 9 @.@.4.m 4.m m m q+m q+q+m { q+q+q+J J u+. . . ",
+" I C ,+Z Z ;+w r+z+>+Y y+:.H h p+p+0 0 y y @.v+4.4.4.m m m m m m m m q+q+q+q+q+q+q+m u+. . . ",
+" k ,+q.,+;+O f+w w+z+l y+:.8+....p+p+ +0 0 y @.@.@.4.4.4.4.m m q+m q+m { { q+q+J q+J q+J u+. . . ",
+" | C q.,+Z ;+f+w w+z+>+Y y+:.8+..p+p+>.0 0 v+v+v+@.4.m m m m m m { q+{ q+q+q+{ { { q+J q+q+q+u+. . . ",
+" O q.Z Z ;+f+w r+z+I >+Y x H .+..p+>. + +0 m+v+v+4.@.4.m m m m m m { m { { q+q+q+m { m q+q+J J u+. . ",
+" Z Z Z Z O f+8.r+w+I l >+x :.8+..p+>.>. +0 0 v+@.4.@.4.m 4.m m m m m m m m m m m m m m { { m q+q+m . . . ",
+" 3.;+;+;+;+8.w r+z+I >+y+y+:.H ....p+>.0 0 y y 9 @.4.m m m m 4.m m m m m m m 4.4.4.m m m 4.m 4.m m { q+J . . ",
+" ;+;+;+O 8.w r+z+z+l Y y+:.H 8+h p+p+ + +0 0 @.i.v ).).$ u+4.m 4.4.4.4.4.4.4.4.4.4.4.4.4.m 4.m 4.m m 4.q+. . ",
+" x 8.8.w r+r+T.I I >+>+y+:.8+....p+p+>.0 0 0 v+@.5+C.6 6 C., 4.4.4.4.4.v+4.v+4.4.4.v+v+4.v+4.9 4.4.4.m 4.4.m J . ",
+" p 8.r+r+w+w+I I I >+Y y+x H H ..p+p+>. + +0 v+y @.v 6 e+6.=.S 4.v+v+v+v+4.v+4.v+v+9 v+9 9 4.9 4.9 9 @.9 4.4.4.P.. . ",
+" E+!.!.z+z+@+I >+y+y+:.H H .+..h p+>. +0 0 0 m+v+@.v 6 e+e+=.S 4.v+9 v+m+v+m+v+v+9 9 v+m+m+v+m+9 9 9 @.9 @.4.9 4.D+J ",
+" I I I I l >+>+>+y+x :.H .+..h p+>.>.0 0 y y v+v+@.7.6 6.6.=.S @.v+m+m+v+m+v+m+m+0 m+m+m+v+m+v+y 9 m+m+9 9 9 @.@.J . ",
+" F Y >+>+Y y+y+:.:.:.H H ..#.p+>.p+>. +0 0 v+9 y v+@.7.-.6.6.=.<+9 y v+m+m+0 0 0 0 0 0 m+ +m+^.m+0 m+9 m+m+~.9 9 9 @.`.. ",
+" Y y+y+y+y+x :.:.:.H .+..h h p+p+ + +0 0 y y y 9 y y $ 6 e+e+=.S 9 + +m+ + + + + + + + +0 +0 + +m+ +m+m+m+m+m+~.9 D+. ",
+" P.H x :.:.:.H H ...+..h p+p+>.>.0 0 0 0 v+m+v+y m+y y v 6 6.6.=.<+y 0 +0 + + +^. + + +2 +2 +^. +0 ^.0 m+m+m+m+m+~.9 @.P. ",
+" >.:.8+8+..H .+....#.p+p+p+>.>.0 +0 y y 0 v+y 0 v+m+y 7.6 6.6.=.<+m+ + +2 + +2 p+2 2 2 +2 +2 +2 2 + + + +m+^.m+m+~.`.. ",
+" ~.........#...h h p+p+>.>. + +0 0 0 y v+y m+9 m+0 0 y v 6 s 6.=.r.m+ + + +2 +2 2 p+2 p+2 2 2 p+2 2 2 2 2 + + + +^.^.m+~.9+ ",
+" p+h p+h p+p+p+p+>.>.>. +0 0 0 y 0 v+9 y 9 v+y y m+m+9 7.F.6.6.=.<+ +2 p+p+p+! p+p+2 p+! p+! p+! 2 p+2 2 2 2 2 ^. + +m+m+9 P. ",
+"t 0 p+>.>.p+>.>. + +0 0 +0 0 0 v+y v+9 v+y 0 0 v+y 0 m+5+6 s 6.=.r. +2 2 2 p+p+! ! ! h h h h ! h ! h h 2 2 2 2 2 +2 ^.^.^.m+D+",
+"v+ +>.>. + + +0 +0 0 0 v+0 v+v+v+9 9 9 m+9 9 9 _ <+m+y 7.6 6.6.=.r.^.m+r.2 ! ! h h h .+.+h .+h h h h ! h h ! p+2 2 +2 +^.m+m+",
+"y 0 0 0 0 0 0 0 0 0 0 0 v+v+9 @.@.@.@.v+0 0 0 0 g u <+W.v F.s 6.=.].W.u.Q ^..+.+.+.+h .+.+.+.+.+.+.+h .+! h ! h ! ! 2 2 ^.>.^.m+",
+"0 0 0 0 0 0 0 v+y v+v+v+9 v+@.v+v+v+v+9 9 9 m+y g ^ ^ 5+c.6 6.s F.).d ^ b.p h ...+.+] 8+8+8+8+8+8+.+.+.+.+.+.+! h 2 2 2 2 2 2 ^.",
+"y v+v+v+v+v+y v+y @.v+@.@.v+4.4.@.@.@.v+0 y 0 m+g H.F.=.F.s 6.6.F.6 F.F.Q #..+.+:..+8+:.] ] ] ] E+E+8+8+.+.+.+h .+h ! ! 2 2 +^.",
+"v+y y v+v+v+9 9 9 y @.~.9 @.@.@.@.9 9 ~.9 m+m+~.m+w.1 '.6.6.6.6.6.s '.0./ ! 8+8+8+H ] 8+8+8+] 8+8+8+] V.8+V.! )+h )+h 2 ! 2 2 +",
+"4.v+@.@.@.4.t+^+V V ~+[.[.~+~+~+~+~+: ~+: ~+~+: ~+*+t.a.%+s 6.6.s -.3 7 B ~+: : ~+: ~+~+~+: ~+: : l.: : l.: {.3.h .+.+! ! ! ! 2 ",
+"4.4.4.4.@.m R.F+++2.2.2.2.2.++++++++++i ++i i i i i+h.d.Q F.s s 6 p.) g+I.E E E E.E.E.E.E.E.E.E.E.E.E.F+E.F+K U.V.8+.+h h 2 2 +",
+"m @.@.4.@.m 2+F+2.2.2.2.2.2.++++++++++++++i ++i ++i _+t+ .Q F.F.@ X.; a E E E E E E E E.E E E E E E.E E.E.E./.;.V.H ] )+8+! ! 2 ",
+"m 4.4.m m m p l.o o *+*+*+o o *+*+o *+*+*+o V *+*+*+P 2 ^.w.Q a+<.h 3.^+o o V o o V V o V V V V V V ~+~+V B j B+] ] 8+8+)+..! 2 ",
+"q+m 4.4.m m m *.G+_ _ _ *.*._ _ G+_ 9+F g.D 7+D <.D.<.7+7+2 7+<.p T T T k 3.3.3.3.3.B+R R R R 3.R R R 3.3.8 V.B+E+E+] 8+.+8+)+! ",
+"m m m m 4.m o.$+f 1.1.f 1.,.1.1.- z.> 4+f f f 1.f f f f (.J.k.f.L f f f f f f L f A.+.} - f L f L L L f L $+3.E+E+U E+] ] )+..2 ",
+" . m m m m J [ f &.|.j+|.|.j+|.c b+M }.L L.L.j+j+L.j+L.&.O.3+Q.- d+&.L.L.(+L.(+&.#+A.0+f.O.A (+(+(+A (+A 5.A.+.B+E+E+E+H )+V. ",
+" m m m m q+m t X !+j+|.|.j+j+j+j+!+C+= '+W L.j+L.j+L.L.L.&.< $.'+- _.(+(+(+(+(+(+&.W j.e 5 #+(+(+(+(+(+(+A O.B.+.E+U E+] ! F ",
+" . u+m m m q+J [ [+&.&.&.&.&.&.&.&.L v.}.f d+&.d+d+d+_._.~ K.=+e.$+_._.d+_._._._._.q %.$.} l+_.5._.5.5.~ 5.#+f.y.S.U U B+] ^. ",
+" u+m m m q+{ t M $+G.G.G.G.G.$+G.r = g.M $+G.G.G.G.N N N G.B.k x.A.N N N N N -+N N f.]+s.f.N N -+N N N G.N 4++.B+U U E+E+! 9+ ",
+" . q+{ q+J t *.*.*._ _ _ _ _ g.F F 9 % 7+7+<.p <.t+p T T T x+3.3.R R 8 ;.8 ;.;.G ;.n+G G G G G G G G U.U.U.U 6+S.S.U E+# ",
+" u+q+q+J 3.m./.K /././././.Z./.Z.K K /./.K K /.Z.Z./.Z.Z.& /.& /.& & Z.& Z./.Z.& & & Z.& & & & & & & & & o G S.6+n U # 9+ ",
+" . q+J ]+}+++2.2.2.2.2.2.2.++++++++++++++++i i i i i i i i i+i+i i+i+I.E I.i+i+E E i+i+E E i+E E E E.E K ' n n S.S.E+ ",
+" q+{ J 8 a E E.E.E.E.E.E.E.E E.E.E.E.E.F+F+E.F+E.F+F+F+}+( ( F+}+( ( ( ( ( }+}+}+}+` }+}+}+` ` ` ` }+` & 2+n n n V.% ",
+" . u+J F n.4 4 4 4 4 4 4 4 4 9.{+4 4 9.9.9.9.9.9.9.+ A+9.A+A+Y.A+A+A+A+A+Y.Y.Y.Y.P Y.P P P Y.{.Y.A+A++ 4 U.n 6+n U )+ ",
+" J J J J J J t J { { { D+`.9+9 % % m+^.^.2 2 2 ! ! ! V.H E+E+E+S.S.n n+6+n+n+@+@+z b b b b b z @+@+n+n+n 6+n S.7+ ",
+" . u+J J J J J J m 4.@.9 @.9 m+^.^.^. +2 ! ! ..8+] ] E+E+S.n n 6+>+l l T.T.b * b * c+c+* * b b b @+n+l 6+n S. ",
+" P.{ q+q+q+q+q+m { m 4.4.9 9 m+0 0 +2 2 2 ! h 8+8+8+] U U U n n n+l @+@+b @+b * !.* * * * * z @+l @+l n U.F ",
+" . J { { J J q+m m 4.@.9 9 9 m+^. + +2 p+! h .+8+8+E+U S.y+n n l l l l @+@+b b b b b b b b @+@+l l n+n n ",
+" J J J q+q+m { m D+9 9 9 m+0 m+ +2 2 2 ! h h .+8+8+E+E+S.n n n >+l @+@+@+@+b b b b b b b @+T.l 6+l T ",
+" . . q+J J q+{ m m 4.@.9 m+m+m+0 +2 p+! ! .+8+] ] ] U :.y+n n l l l @+@+@+@+b b @+@+@+@+@+@+n+n n ! ",
+" . J J q+q+q+m 4.4.@.9 9 m+0 ^. +2 2 2 h h .+8+8+E+] U S.y+n n n l l l @+@+@+@+@+@+@+@+n+n+l n % ",
+" . . J J { q+m 4.@.9 9 m+0 ^. + +2 2 2 h h 8+.+H E+U U S.n >+n >+l l l l l @+@+l n+l >+n 6+! ",
+" . q+q+q+m D+4.4.@.9 9 m+0 m+ + +2 h ! h .+8+] ] ] U U S.S.n n n n l l n+l n+n+l n+n+n % ",
+" . P.J m m D+4.@.9 9 m+m+^. + +2 2 ! h .+h 8+] H E+E+U S.n n >+n n l 6+>+n+n n n n V. ",
+" q+J { 4.4.4.@.9 9 m+0 ^.2 +2 2 ! ! .+.+8+] ] U U U S.S.n n 6+n n n n n 6+T ",
+" . u+{ 4.`.@.9 m+m+m+m+^. +2 2 p+! ! h )+8+8+8+E+E+U E+S.U S.n n S.n U ] ",
+" { m 4.9 9 9 9 m+m+ + + + +2 2 #.)+..8+.+] 8+] E+U E+S.U U U U p ",
+" . J 4.4.9 9 m+m+^.^.2 2 2 ! #.! ! V.8+8+8+] ] E+] E+E+E+E+V. ",
+" D+@.9 9 m+m+^.m+^.2 2 2 ! ! h ! V.8+V.8+] E+# % ",
+" . D+9 y ^. +^.^.2 +2 2 ! h )+h V.! 2 p ",
+" 9 m+m+0 ^.2 2 2 2 2 2 % "};
diff --git a/arts/builder/pics/Synth_DEBUG.xpm b/arts/builder/pics/Synth_DEBUG.xpm
new file mode 100644
index 00000000..4a0a09af
--- /dev/null
+++ b/arts/builder/pics/Synth_DEBUG.xpm
@@ -0,0 +1,319 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 248 2",
+/* colors */
+" c #8B94BA",
+" . c #525A8C",
+" X c #374482",
+" o c #8992B8",
+" O c #3B457C",
+" + c #354280",
+" @ c #444E92",
+" # c #323E7D",
+" $ c #6E77A4",
+" % c #3F4E8D",
+" & c #2C3877",
+" * c #444C7E",
+" = c #283473",
+" - c #253070",
+" ; c #525985",
+" : c #242E6F",
+" > c #333E81",
+" , c #5F6995",
+" < c #1F2A6A",
+" 1 c #1E2869",
+" 2 c #949DBF",
+" 3 c #2D387B",
+" 4 c #7E88B0",
+" 5 c #2F3973",
+" 6 c #2B3679",
+" 7 c #575F8D",
+" 8 c #555D8B",
+" 9 c #40487D",
+" 0 c #4D568D",
+" q c #4F5785",
+" w c #44538E",
+" e c #555FA2",
+" r c #1F2A6D",
+" t c #1E286C",
+" y c #8E97BC",
+" u c #283279",
+" i c #253076",
+" p c #364380",
+" a c #8289B0",
+" s c #2F3B79",
+" d c #404B8D",
+" f c #2E3978",
+" g c #4F599F",
+" h c #565F92",
+" j c #404C83",
+" k c #2F386F",
+" l c #1A2361",
+" z c #384585",
+" x c #364383",
+" c c #303D7D",
+" v c #2F3B7C",
+" b c #2E3B7B",
+" n c #1D2767",
+" m c #505E99",
+" M c #283375",
+" N c #384388",
+" B c #374187",
+" V c #4E598D",
+" C c #384174",
+" Z c #42508B",
+" A c #1E296B",
+" S c #1D276A",
+" D c #6C739D",
+" F c #2A357A",
+" G c #7983AD",
+" H c #3A4883",
+" J c #263176",
+" K c #676F98",
+" L c #28326E",
+" P c #242F74",
+" I c #9EA5C4",
+" U c #232D73",
+" Y c #42508E",
+" T c #41508D",
+" R c #3D4C89",
+" E c #2D3876",
+" W c #374483",
+" Q c #273270",
+" ! c #38417A",
+" ~ c #313E7D",
+" ^ c #5D6591",
+" / c #5C6390",
+" ( c #323B74",
+" ) c #2A3676",
+" _ c #354084",
+" ` c #232E6F",
+" ' c #757CA5",
+" ] c #1F2A6B",
+" [ c #323D77",
+" { c #1E286A",
+" } c #1C2668",
+" | c #9299BE",
+". c #293478",
+".. c #273276",
+".X c #3E467C",
+".o c #4C588D",
+".O c #222C71",
+".+ c #3A4278",
+".@ c #212C70",
+".# c #202A6F",
+".$ c #1F2A6E",
+".% c #1E286D",
+".& c #363E74",
+".* c #1D286C",
+".= c #353E73",
+".- c #3E4D89",
+".; c #3D4B88",
+".: c #7E85AA",
+".> c #2B3573",
+"., c #7C83A8",
+".< c #394784",
+".1 c #384583",
+".2 c #646C97",
+".3 c #3A447B",
+".4 c #636A96",
+".5 c #868FB5",
+".6 c #6872B2",
+".7 c #212B69",
+".8 c #3F498D",
+".9 c #7981A8",
+".0 c None",
+".q c #5B66A5",
+".w c #212B6C",
+".e c #1F296A",
+".r c #414E88",
+".t c #1D2768",
+".y c #2C377A",
+".u c #1C2567",
+".i c #3B458C",
+".p c #3D4A84",
+".a c #293577",
+".s c #3C4883",
+".d c #2C3670",
+".f c #4B5A95",
+".g c #646E9D",
+".h c #3A4681",
+".j c #394680",
+".k c #475691",
+".l c #172058",
+".z c #485292",
+".x c #323D83",
+".c c #5662A3",
+".v c #44528E",
+".b c #34407B",
+".n c #5D6696",
+".m c #303B81",
+".M c #1F296D",
+".N c #42508C",
+".B c #2E397F",
+".V c #414E8B",
+".C c #313C78",
+".Z c #1D276B",
+".A c #404E8A",
+".S c #3F4E89",
+".D c #596292",
+".F c #6D759F",
+".G c #2A357B",
+".H c #515F94",
+".J c #3D4A87",
+".K c #3B4885",
+".L c #485695",
+".P c #5F6A9B",
+".I c #35427F",
+".U c #242E6B",
+".Y c #707BA5",
+".T c #4C5485",
+".R c #232C6A",
+".E c #4A5283",
+".W c #303C7A",
+".Q c #202A67",
+".! c #343D74",
+".~ c #2D3877",
+".^ c #1D2664",
+"./ c #3C4A89",
+".( c #454E7E",
+".) c #2B3675",
+"._ c #68719D",
+".` c #293473",
+".' c #283272",
+".] c #485498",
+".[ c #39457C",
+".{ c #354282",
+".} c #334080",
+".| c #424E92",
+"X c #323C7F",
+"X. c #424F88",
+"XX c #6973A1",
+"Xo c #2A3477",
+"XO c #414A7D",
+"X+ c #4A5993",
+"X@ c #495792",
+"X# c #253072",
+"X$ c #43518C",
+"X% c #333F79",
+"X& c #6F78A0",
+"X* c #465085",
+"X= c #1C2669",
+"X- c #2C367C",
+"X; c #2F3975",
+"X: c #515E93",
+"X> c #2D3773",
+"X, c #5E69AD",
+"X< c #4F5C91",
+"X1 c #7882AC",
+"X2 c #29336F",
+"X3 c #232E73",
+"X4 c #888FB5",
+"X5 c #49548B",
+"X6 c #202A70",
+"X7 c #868DB3",
+"X8 c #333F7C",
+"X9 c #404F8C",
+"X0 c #3F4D8B",
+"Xq c #2F3B78",
+"Xw c #4D579C",
+"Xe c #3B4787",
+"Xr c #26316F",
+"Xt c #49568E",
+"Xy c #252F6E",
+"Xu c #344180",
+"Xi c #374279",
+"Xp c #57649F",
+"Xa c #4A5385",
+"Xs c #303D7C",
+"Xd c #828BB2",
+"Xf c #30397C",
+"Xg c #646EAF",
+"Xh c #2E397A",
+"Xj c #464F81",
+"Xk c #313A73",
+"Xl c #3C498B",
+"Xz c #343F83",
+"Xx c #6D77B1",
+"Xc c #222D6E",
+"Xv c #222B6E",
+"Xb c #1D2769",
+"Xn c #546195",
+"Xm c #263175",
+"XM c #757FA8",
+"XN c #455490",
+"XB c #202B6F",
+"XV c #43528E",
+"XC c #1F296E",
+"XZ c #323E7A",
+"XA c #1E296D",
+"XS c #505C9E",
+"XD c #3B4886",
+"XF c #2A3472",
+/* pixels */
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0X#... u u i PX3.O.# A n.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.> # N B.x.m.B.G u u i P U.O.OX6X6.M l l.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0Xe @.|.i N B.x.m.B.G u u i P U.O.OX6.#.#XCXC t l.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 p g g.] @.|.i N B.x.m.B.G u u i P U.O.OX6.#.#XCXA.%.% tX= l.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.c.c e g.].|.8.i N _.x.BX-.G u.. i P U.O.OX6.#.$XCXA.% t t.*.Z }.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0XwX,X,.c gXw.].|.8.i N _.x.BX-.G u J i P U.O.OX6.#XCXCXA.% t t.Z.Z.ZX= l.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.6.6X,X, e gXw.].|.8.i BXz.m.BX-.G u J i P U.O.@X6.#XCXCXA.% t t.Z.Z.Z S S.u.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0X$.6.6XgX,.c e g.].].|.8.i B.x.m.BX- F u i iX3.O.O.@.#.#XC.M.% t t.*.Z.Z S S S S }.l.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0X<Xx.6.6X,X,.c gXw.].|.8.i N B.x.m.B.G u u i PX3.O.O.@.#.$XCXA.% t t.Z.Z.Z S S SXbX= }.l.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0X:Xx.6.6XgX,.q e g.].].|.8.i N _.x.BX-.G u.. i P U.O.OX6.#.$XCXA.% t t.Z.Z.Z S S SXbX=X= }.l.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0X<Xx.6.6XgX,.c eXw.f.z @.8.i N _X Xh.yXo. .. J i P U.O.@XB.#XC.MXA t t.Z.Z.Z S S SXbXbX=X= }.u.l.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0X$Xx.6.6XgX,.q eXS m.PXn.f d.i BXz v.C E.) M J i iX3.OX6.#.#.$XC.M.% t t t t.Z.Z S S SXbXbX= } }.u.l.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.6.6.6XgX,.q.cXp.PXXX1.P.f.8 B.I ! 9Xa *.3.>X#X#X3.OXv.w.7.e t.%.MXAXA.Z.Z.Z.Z t t t t { SXbXb } }.u.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.6.6.6XgX,.q.c.qXg.5 | I $ 0.J x 9 8._ a.F /.& -X#.OXc.R.U L.7.M.M.#.#.#.M.M.M.M.M r.w r.M A t { {Xb.t.u.0.0.0.0.0.0",
+".0.0.0.0.0Xw.6XgX,X,.q.c eXS.g.5 |.gX5X5Xa . ^ ,.2.4.4.XXFXF.>.&XO C.=.U.w.wXv.w.w.UX2 LXr.w.w.w.w ] ] 1.Q n n.t.t l.0.0.0.0.0",
+".0.0.0.0.0X,X,X,X,.q eXSXwXw.nX7X7Xd.n.V h.Y.F K 7.T.D._X*X;.3X*.2X7 ,.(X2XcXc :XrX2.&Xj 9 !X2XcXcXc.w.7.7.R.7.Q.Q 1 n.0.0.0.0.0",
+".0.0.0.0.cX,X,.c.c e g g.].z.n oX1XX.n 0.P G ^ * * *.T 8 9X; OX5.F 2 / CX2 -.' E !Xj 8 K 8XO.d :.U.U L k CXO C k.U.Q.Q 1.0.0.0.0",
+".0.0.0 p.c.c e e g gXwXw @ d h $ h hXnXXX7 qX;.!.3 9.(.+X;.X ..9 I 7 kX2X# E.s.D.9X7 |._XaXkXr L.d C ;.2.,.4 ; k.7.7.w.^.0.0.0",
+".0.0.0 g e g g gXwXw.].] dX5.nX4.gX5 h.g._.F *.).&Xj.X CX>.'.&.T.2.:.( L Q M E.[.D aX7 , 9X%X>.+.E ; ^.2.F K.4.+ L.R.R <.0.0.0",
+".0.0.0 g gXwXw.].].] @.|.r hXXXd.n.J hXM._ /.+.`.& 7.XX> QX#.dXO ; K C L.' M E.b 7X4X7X7 7 !.3.[ 7.:X& K.2.4 D.9.E k L.UXc.0.0.0",
+".0.0Xe.].].].].].|.|.8.8X..g.gXXX5 X VX1 D / * ( 9 7.+X2.' M k 8 ; q k.'.`. .) [ .X7.:XM ..3 j . K.: ^Xj.(.( 7X&.( k LXyXy.Q.0.0",
+".0.0 @ @.|.|.|.|.8.8.i NX5XM.g h.p #Xa.:.F.n VXj.T 8.&.'.' M C D ; C.d.a 6.y.)X;.TX7XM._.T.[ V.FXM.: q.!.!.=.E D * k LXr -Xy.0.0",
+".0.>.|.|.8.8.8.8.i.i N _.s .X*.sX8XfXj.YX&.F.4.D.T * 5 M.'X2.+X&.EXk.d 6.y 3X;.+ 7X7.F.D.T j.D.9X& K * 5.=.+.E ^.X.d L.'.' Q.Q.0",
+".0 #.i.i.i.i.i.i N N _ >.}.hX8Xf 3.y.X.g.Y a GXM 0X%.>Xo.' k.( '.(.d.) 3 3 b [Xj.4 o K.TX5X*.2X4.F 7.+X;.=.(.T ; C.dXF.).` =.Q.0",
+".0 N N N N N B B B _.x.mXfXf 3.y 6. X; 9Xj . qXa !X>Xo. .> C.( / CX> & v b bXi /.FXd.n jX*X5._ y D q.+Xq.+ ;.TXj.=X>.>.).).>.'.0",
+".0 B B B _ _Xz.x.x.x.m.B.BX-X-X- F.. MXFX>.! [.C.). . F 5 *.(.(.! f b cXs.WXOX&XM 4 h.h jX5.F I KXj.+.CXO.2 q 9 ( E E f &.).>.0",
+"X#.x.x.x.x.x.m.m.B 3 3.y.G.G F F u..Xm.' Q.'XF.)Xo. F.yX>.&.!.!X; b c > cXZXjX&XXXXX5.j.pXa._ I ' 7Xa j 8.F q.+ (Xq f f f &.)XF",
+"...m.m.m.B.B.B.B.y 6 6 &. u u u.. J.. J.... u. F.y.y 3.~X; f f vX >Xz #.bXa.F.P.D j p.hXj K I a $.g.n D.9 qXi [Xs.W.W s f.~.>",
+". .BX-X-X-.y 3 s ! 9 O !.)..Xm i PX#X#.' M.. u F.y 3 3 3XhXh sXsX >Xz _.}.I.hX5X*.r.h W.h j ^Xd 4 GXM $.F._XjXiX% #XsXs.W s f.)",
+" u.G.G F F.yX8 j.D '.nX5.CX# PX3X#.'.`.> = M. 6.y.y 3.B v c c >Xz _.{ x.{ + X.h.<.1.<.<.< j ..Y.: X4X7.F.D j.b.bXu.} #XZ.W s E",
+" u u u... 3.s h.F a.n jX>X# -XF (XO OXi.> MXo 6 &.~ fXq.WXs ~ > _ x x z W W W.<.<.<XeXeXD.K.r V 7 , ,.n VX*.h p + +Xu.} # ~.W f",
+" i u i..Xo sX5 'Xd | ^ !XF :.> 9 7 ' , q ( M.a 6 E.b ! O !X8 #Xz x x z zXeXeXeXeXl././Xl././.p.p jX*X*X* j.s.1.1 X X +.I.} #Xs s",
+" P i P iXm M *.Y.9.:.E.dXr :.! 8 DX7 ^ *Xk.`X>X%XO . 8.DXa.s.I.{ x z z z z.<XD././XlX0X0 RX0.;.J.p.p j.J.K.K.<.<.<.1 X p.I.}X8.W",
+"X3 P P P U :.+.F.F.F.3 : :Xy 9 $X7 I ^.+ 5.>Xi .._ 4X7 o D ..s.{ W z z H.K.p.J RXl % % % % %X9X0X0X0 R R R R./XDXD.<.1 X p.IX8Xs",
+".O U U UXcXy 9 '.4 .Xk.wXc.U O.F.,X7 q 5XkXk.E D.F $ GX7.F hX..<.K.pX..o.o VX..-X0 % % %.A.S.S.S.SX0.AX0X0X0 R.;.JXD.<.1 X +.I #",
+".#.O.O.O.w L.(.:.D.X L r.wXc.+ DX& 'XOX2 (XO ,X4 '.P.YXd.F.n.o.rX5X<.P.9XM.YX: Z.V Y Y Y.AX.X.X..A.V T T TX9X0 R.;.J.K.<.1 X.IX8",
+" A.O.OX6.U.& ; '.EX>.U.M.wXyXO ' K / CX2 C 7 ^.2 8X*.nXMXX.PXnXtXn.gXM 4XM.HX$ Z.NX.X5 V.D.D.D.o Z Z Y T TX9X0 R.;XD.K.<.1 p.b",
+" nX6.#.#X2 q ^X&.X.U ]XA.wX2Xa.: ^.(Xk LXO., ^.T 9.[ 0 $XX.g.PXn $Xd | I GXn.vX$ Z.o ,X&.5.5 o.2.oX$XV YXV.NX9X0 R.JXD.<.h p.b",
+".0X6.M ]Xk ^ / 7Xk < t t.U ! 8.: ;.= k.d.(., ;.3 O.j V $.g.nX:Xt.g a y IXdXXXn.kX< h.gXM 4 o y.Y.n.o w wXNXV.N.VX0 R.J.K.< X.0",
+".0.M A.7.+ D 8XO L t t tX2.T.4.,.(X2 k.= ;.,.E [ !.sX< $.PX:X5.r.D 4 I G.PXnX<.P GX4 2 | y 2 a $X:.kXNXNXNXV.N.A.-.JXD.<.j.0",
+".0 l.e.7 k.T.+.d.7.Z t.eXk / ,.4.+ L.=.( ^.: q.b 9X5.n $ hX$.r.J hXd o |.YXn.nXp.Y .5 a.YXXX1 4.YXn.kXN.kXN.vX$X9X0 R.J.K [.0",
+".0 l {.7 L.! L.w {.Z 1.7.+ D ^ ;XkXr C ,X&.: . !X*.n.gXX V.p.s.s 8X7.5 oXXX:.P $.5 IXd $.PXn._XdX1.YXnX@.k.k.kXNXV.N.A.-.J.KX%.0",
+".0.0XbXb.e.R.e 1 S t 1.7.! 7.( CX2Xy.= / D.9.D j 8XX.P.DX* H.p j ^ X7 4.g.H.g G o IX1.PXn.H.g oXMXXXnX+X@.L.kXN.vX$.V.-.J.s.0.0",
+".0.0 l.Z S S S.Z t t.t.w kXj.! LXyXy.! 7 K.9.4 ..2.9.nX5.p.<.pXa K 2Xd.Y.PXnXX.5 y 2 $Xn.H.H.g yXM.P.H.fX+.LX@.k wXV.V.- RXi.0.0",
+".0.0.0.Z.Z.Z.Z.*.Z.ZXb 1.RX2.U.UXy - k.( / '.F K.2 ,Xa.s.1.< j 7X& yX1.g.PXn $ y y ._.HXnXn $ y.Y.P.H.f.f.fX@.kXNXV.N.A R.0.0.0",
+".0.0.0X=.*.Z.Z.Z.Z.ZX=X= 1.e.wXc -X#XF C q.F.9 a.2.T.h p X.<X*.F G $.n.nXpXM 2 a.P.HXn.P.Y y $.n.H m.f.fX+.kXNXV.N.A.p.0.0.0",
+".0.0.0 l.Z.Z.Z.Z.Z.ZX=X=Xb A.wXcX#X# Q.d.+Xj.T 8Xj O ! p X.<X5 ' GXd.gX<.HXnXM I yXd.gXn.P $X1.5XXXp m m.f.fX+.kXN.v.N.A.j.0.0.0",
+".0.0.0.0 }.Z.Z S S S S S t rXc `X#X#.' =X> (X% !.bX8Xu x X.h V G G G.nXtX+X<.Y I |XdXXXpXXXd 4 4.gXn m m.f.fX+.kXNXV.N.J.0.0.0.0",
+".0.0.0.0.0X= S S S S S S t.wXc `X#X#.' =.>X>X;.CXZ #Xu x X.hX*.P.P.PX<.vXtX< $ I 2 oX1 $X1 o 4XM.P m m m.f.fX@.kXNXV.S.0.0.0.0.0",
+".0.0.0.0.0 l S S S SXb S t rXc `X#X# M.a ) &Xh s c.} + x X.h j.o V V.vX$XtX<XX 2 2 | y y GXXXp m m m.f.fX@.kXNXV.h.0.0.0.0.0",
+".0.0.0.0.0.0.u SXbXbXbXb {.M.wXcX#X# MXo ) 6 f b c.}Xu x X.1.s.rX. Z Z.N wX@.P 4 o | y o.5.Y.PXn m.f.f.fX+.kXN w.r.0.0.0.0.0.0",
+".0.0.0.0.0.0.0 }X=X=X=Xb S A.wXc -X# M M ) &Xh v c.}Xu.{ x W.<.K.J RX0X9XVXNXn $ 4 | y .5 4XXXp m.f.f.fX+X@.kXN Z.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.l }X=X=X=Xb t.wXc `X#.' = ) 6 f b c #.} + x W zXD./ RX0 T.NXVX@Xn.P $ $.YXXXXXp m.f.f.fX+X@.kXNX$.[.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.l } } }Xb {.w.w `X#X# M ) & fXhXs ~.}Xu x W.<XD./ RX0X9X9 Y wXtX<XnXnXpXnXn m.f.f.fX+X@.kXNX$.3.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.l.u } } { A.wXc -X# = M ) & f bXs #.} + W z.<XD./ RX0X9.NX$ w.kXtX+X<.f.fX+X@X@X@.k.kXNX$.+.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.l.u }Xb.e.wXc :X#.' = ) & f sXs #.}Xu x W.<XDXD.; RX0X9.NXV.vXNXNXN.k.k.k.k.k.kXNXNX$.3.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.l.u.t A ].w ` -X# = ).) & f bXs #.} + x.1.<XD.J.; RX0.V.N.NX$XVXVXNXNXNXNXNXN w Z.[.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.u 1 ].wXc :X#.'.`.) & f b.W ~ #Xu + X.1.<XD.J.; RX0.AX9.NX$XVXVXV.vXVXVXV.r.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0 l 1.wXc ` - Q =.`.) & f sXs #.}Xu + X.1.<.KXD.J R.-X0.A.V.V.N.N.N.N.S.h.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 1.wXc :Xr.'.`.).) f f.WXs #.}.I p X.1.<.KXD.J.J R.-.-.-.A.A.A.J.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.^.7 ` - Q.'.`.) & f s.WXZ #.}.I p X.1.<.<.KXD.J.J.J R R.p.j.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.QXy Q =.>.) & f s.W ~ #.}.I + X.1.h.<.<.K.K.sXi.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.Q.Q.'.>.).~ f s.WXsX8X8.I.I p p X.j [X%.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",
+".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0XF.>.) E f s.WXs #X8.b.b.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
+};
diff --git a/arts/builder/pics/Synth_DIV.xpm b/arts/builder/pics/Synth_DIV.xpm
new file mode 100644
index 00000000..c424ce7a
--- /dev/null
+++ b/arts/builder/pics/Synth_DIV.xpm
@@ -0,0 +1,1350 @@
+/* XPM */
+static char * Synth_DIV_xpm[] = {
+"64 64 1283 2",
+" c None",
+". c #253073",
+"+ c #273276",
+"@ c #293378",
+"# c #283278",
+"$ c #263077",
+"% c #252F75",
+"& c #232E74",
+"* c #212B71",
+"= c #202A6E",
+"- c #1E296A",
+"; c #1C2667",
+"> c #2B3671",
+", c #313D7B",
+"' c #384288",
+") c #353F87",
+"! c #323D83",
+"~ c #2F3A80",
+"{ c #2D377D",
+"] c #2A357B",
+"^ c #29347A",
+"/ c #273177",
+"( c #253076",
+"_ c #232D72",
+": c #222C72",
+"< c #212C71",
+"[ c #202B70",
+"} c #202A70",
+"| c #1F296E",
+"1 c #1B2463",
+"2 c #3C4988",
+"3 c #434D95",
+"4 c #414C93",
+"5 c #3D488D",
+"6 c #202A6F",
+"7 c #1F2A6F",
+"8 c #1E286C",
+"9 c #37437E",
+"0 c #4F59A0",
+"a c #485399",
+"b c #3B458D",
+"c c #283379",
+"d c #242E74",
+"e c #1E296D",
+"f c #1E286D",
+"g c #1C2669",
+"h c #5862A8",
+"i c #555FA6",
+"j c #3F4B90",
+"k c #1F2A6E",
+"l c #1D276B",
+"m c #1C2668",
+"n c #4B5A97",
+"o c #616CB3",
+"p c #5C67AF",
+"q c #4B579B",
+"r c #2E397F",
+"s c #263177",
+"t c #253075",
+"u c #6872B4",
+"v c #343F84",
+"w c #222C71",
+"x c #212B70",
+"y c #1B2666",
+"z c #1B2366",
+"A c #45538B",
+"B c #445194",
+"C c #2B367B",
+"D c #263076",
+"E c #232E73",
+"F c #1D266B",
+"G c #1E266C",
+"H c #1A2264",
+"I c #1D276A",
+"J c #171F57",
+"K c #4A5996",
+"L c #273277",
+"M c #242F74",
+"N c #1A2664",
+"O c #1E296C",
+"P c #1D296B",
+"Q c #1E2A6C",
+"R c #354186",
+"S c #2C377B",
+"T c #202B6F",
+"U c #6672BC",
+"V c #666EB4",
+"W c #5E6AB4",
+"X c #5A66AC",
+"Y c #565EA4",
+"Z c #525EA4",
+"` c #4E5AA2",
+" . c #4A569C",
+".. c #465296",
+"+. c #424E94",
+"@. c #3E4A8E",
+"#. c #3E468C",
+"$. c #36428C",
+"%. c #363E84",
+"&. c #626EB4",
+"*. c #5E66AC",
+"=. c #5662AB",
+"-. c #525AA4",
+";. c #424A94",
+">. c #3A4A8C",
+",. c #3A468C",
+"'. c #323E84",
+"). c #273278",
+"!. c #4A529C",
+"~. c #464E93",
+"{. c #3A428C",
+"]. c #313983",
+"^. c #2D387E",
+"/. c #2A3479",
+"(. c #263176",
+"_. c #303A7B",
+":. c #353D7B",
+"<. c #303A7A",
+"[. c #252F74",
+"}. c #212A6F",
+"|. c #1F2B6F",
+"1. c #212A6E",
+"2. c #1E286A",
+"3. c #1D2769",
+"4. c #303B81",
+"5. c #2C367E",
+"6. c #293479",
+"7. c #232E72",
+"8. c #313C7C",
+"9. c #475088",
+"0. c #606998",
+"a. c #69709D",
+"b. c #606898",
+"c. c #485189",
+"d. c #303979",
+"e. c #212D72",
+"f. c #222E74",
+"g. c #222A6F",
+"h. c #1E2868",
+"i. c #1A235E",
+"j. c #5A62AC",
+"k. c #35418B",
+"l. c #2F3B80",
+"m. c #485088",
+"n. c #797FAA",
+"o. c #A3A7C3",
+"p. c #B3B6CD",
+"q. c #A3A8C3",
+"r. c #797EA8",
+"s. c #273176",
+"t. c #222B70",
+"u. c #212B6C",
+"v. c #20296C",
+"w. c #4E569C",
+"x. c #323A80",
+"y. c #29357A",
+"z. c #283178",
+"A. c #263075",
+"B. c #263171",
+"C. c #323E7A",
+"D. c #60699A",
+"E. c #A4A9C3",
+"F. c #D3D5E1",
+"G. c #E0E2EA",
+"H. c #D2D5E2",
+"I. c #A5A9C3",
+"J. c #626997",
+"K. c #313D7E",
+"L. c #242E73",
+"M. c #262E73",
+"N. c #262F73",
+"O. c #263273",
+"P. c #222E6C",
+"Q. c #223264",
+"R. c #222D6E",
+"S. c #4E5AA4",
+"T. c #4A5A9C",
+"U. c #303C81",
+"V. c #2D397E",
+"W. c #2C357D",
+"X. c #273378",
+"Y. c #263276",
+"Z. c #252F76",
+"`. c #373F7D",
+" + c #6C729E",
+".+ c #B4B7CE",
+"++ c #E0E2EB",
+"@+ c #EBECF2",
+"#+ c #B4B8CE",
+"$+ c #6C73A2",
+"%+ c #394278",
+"&+ c #243073",
+"*+ c #263277",
+"=+ c #263078",
+"-+ c #26327C",
+";+ c #252D72",
+">+ c #253071",
+",+ c #242F6E",
+"'+ c #232E6E",
+")+ c #46529C",
+"!+ c #425294",
+"~+ c #354182",
+"{+ c #2B357D",
+"]+ c #273178",
+"^+ c #263175",
+"/+ c #242F73",
+"(+ c #333E7D",
+"_+ c #636A9B",
+":+ c #A5A9C2",
+"<+ c #D3D5E2",
+"[+ c #646B9A",
+"}+ c #364181",
+"|+ c #26336C",
+"1+ c #283273",
+"2+ c #2A3674",
+"3+ c #26366C",
+"4+ c #2A3274",
+"5+ c #232E6C",
+"6+ c #212B69",
+"7+ c #464E94",
+"8+ c #2F3B81",
+"9+ c #2D3679",
+"0+ c #2B357C",
+"a+ c #273272",
+"b+ c #273274",
+"c+ c #273076",
+"d+ c #243074",
+"e+ c #253070",
+"f+ c #2D3779",
+"g+ c #4A538C",
+"h+ c #7C82AB",
+"i+ c #A5AAC5",
+"j+ c #B5B9CE",
+"k+ c #A5ABC5",
+"l+ c #7E84AC",
+"m+ c #4E568C",
+"n+ c #2E3A7A",
+"o+ c #2B3779",
+"p+ c #28337A",
+"q+ c #293574",
+"r+ c #2B377D",
+"s+ c #2A367C",
+"t+ c #2A327C",
+"u+ c #293474",
+"v+ c #273273",
+"w+ c #273271",
+"x+ c #3E4A94",
+"y+ c #323A84",
+"z+ c #2E3A7F",
+"A+ c #2A3679",
+"B+ c #2A3579",
+"C+ c #263470",
+"D+ c #263274",
+"E+ c #273377",
+"F+ c #273371",
+"G+ c #27346F",
+"H+ c #293475",
+"I+ c #394382",
+"J+ c #4F588C",
+"K+ c #666F9B",
+"L+ c #7279A3",
+"M+ c #686F9F",
+"N+ c #50598E",
+"O+ c #3C4681",
+"P+ c #2D3777",
+"Q+ c #2D3976",
+"R+ c #2E397B",
+"S+ c #2D3775",
+"T+ c #2B3873",
+"U+ c #2F3B77",
+"V+ c #30397E",
+"W+ c #2F3775",
+"X+ c #2A386E",
+"Y+ c #2E3A7D",
+"Z+ c #293579",
+"`+ c #293575",
+" @ c #293473",
+".@ c #263170",
+"+@ c #2A357C",
+"@@ c #2A3379",
+"#@ c #293278",
+"$@ c #273279",
+"%@ c #2A3378",
+"&@ c #283377",
+"*@ c #283378",
+"=@ c #2C3779",
+"-@ c #303B7E",
+";@ c #3A4482",
+">@ c #3D4781",
+",@ c #3D4683",
+"'@ c #323E80",
+")@ c #2D397A",
+"!@ c #2E3B7A",
+"~@ c #2E387D",
+"{@ c #2F3B7D",
+"]@ c #2E3C7A",
+"^@ c #2F387D",
+"/@ c #2F3B7F",
+"(@ c #313D7F",
+"_@ c #303E7E",
+":@ c #2F387C",
+"<@ c #2E367C",
+"[@ c #2C3877",
+"}@ c #2C3878",
+"|@ c #2C3777",
+"1@ c #2A3676",
+"2@ c #2B3571",
+"3@ c #2B3478",
+"4@ c #283477",
+"5@ c #2A3375",
+"6@ c #2A3474",
+"7@ c #2A3576",
+"8@ c #2B3676",
+"9@ c #2C3778",
+"0@ c #2C387A",
+"a@ c #2C397B",
+"b@ c #2E387B",
+"c@ c #2E3A7C",
+"d@ c #2E3B7B",
+"e@ c #2F3C7C",
+"f@ c #2F3D7C",
+"g@ c #303D7D",
+"h@ c #303D7E",
+"i@ c #313F7E",
+"j@ c #313E80",
+"k@ c #313D7D",
+"l@ c #313E7F",
+"m@ c #324081",
+"n@ c #323E81",
+"o@ c #2E3E7C",
+"p@ c #2D3A79",
+"q@ c #2D3978",
+"r@ c #283677",
+"s@ c #2A347C",
+"t@ c #263372",
+"u@ c #283479",
+"v@ c #283578",
+"w@ c #2B377B",
+"x@ c #2F3C7D",
+"y@ c #2F3C7E",
+"z@ c #303C7D",
+"A@ c #313E7E",
+"B@ c #323E7E",
+"C@ c #333F7F",
+"D@ c #323F7E",
+"E@ c #333F80",
+"F@ c #344081",
+"G@ c #333F7E",
+"H@ c #33417F",
+"I@ c #354183",
+"J@ c #34407E",
+"K@ c #2F3B7E",
+"L@ c #303980",
+"M@ c #2F3C7A",
+"N@ c #2A3279",
+"O@ c #293478",
+"P@ c #2B357A",
+"Q@ c #2B3579",
+"R@ c #2D397B",
+"S@ c #2E397C",
+"T@ c #2E3B7D",
+"U@ c #2F3B7B",
+"V@ c #2F3D7F",
+"W@ c #303D7F",
+"X@ c #313E7D",
+"Y@ c #313F81",
+"Z@ c #334082",
+"`@ c #334080",
+" # c #344183",
+".# c #354284",
+"+# c #35417E",
+"@# c #344284",
+"## c #364386",
+"$# c #364385",
+"%# c #364282",
+"&# c #354383",
+"*# c #344180",
+"=# c #2B3776",
+"-# c #2B3675",
+";# c #283370",
+"># c #29337C",
+",# c #273375",
+"'# c #293477",
+")# c #283474",
+"!# c #2C377C",
+"~# c #2C3875",
+"{# c #2E3A7E",
+"]# c #303C7F",
+"^# c #303D7C",
+"/# c #344181",
+"(# c #344281",
+"_# c #354280",
+":# c #344282",
+"<# c #34427F",
+"[# c #374280",
+"}# c #364482",
+"|# c #374487",
+"1# c #374582",
+"2# c #374586",
+"3# c #384485",
+"4# c #344080",
+"5# c #2D3876",
+"6# c #26327B",
+"7# c #273477",
+"8# c #2A3475",
+"9# c #2A3775",
+"0# c #2C3879",
+"a# c #2E3A78",
+"b# c #2F3B7C",
+"c# c #303C7B",
+"d# c #323E7F",
+"e# c #323F80",
+"f# c #333F81",
+"g# c #334180",
+"h# c #364283",
+"i# c #364382",
+"j# c #374385",
+"k# c #384584",
+"l# c #354482",
+"m# c #384588",
+"n# c #384587",
+"o# c #394585",
+"p# c #394587",
+"q# c #394686",
+"r# c #394687",
+"s# c #374483",
+"t# c #354382",
+"u# c #354282",
+"v# c #2B3775",
+"w# c #2A337C",
+"x# c #283570",
+"y# c #2D377C",
+"z# c #2B3679",
+"A# c #2D3A7C",
+"B# c #323F81",
+"C# c #344182",
+"D# c #334181",
+"E# c #344382",
+"F# c #354281",
+"G# c #364484",
+"H# c #364583",
+"I# c #374482",
+"J# c #384585",
+"K# c #374684",
+"L# c #374685",
+"M# c #374480",
+"N# c #3A4686",
+"O# c #394885",
+"P# c #3A4988",
+"Q# c #3A4A8A",
+"R# c #3A4989",
+"S# c #3A4786",
+"T# c #2F3B78",
+"U# c #2B3674",
+"V# c #343F80",
+"W# c #3B4384",
+"X# c #424D89",
+"Y# c #454F8A",
+"Z# c #454E89",
+"`# c #47518A",
+" $ c #47508A",
+".$ c #475190",
+"+$ c #495387",
+"@$ c #4B5691",
+"#$ c #4C5791",
+"$$ c #4B568C",
+"%$ c #4E5990",
+"&$ c #515B93",
+"*$ c #505B92",
+"=$ c #525D91",
+"-$ c #535E95",
+";$ c #535E94",
+">$ c #556094",
+",$ c #556095",
+"'$ c #556096",
+")$ c #566194",
+"!$ c #576296",
+"~$ c #566297",
+"{$ c #566294",
+"]$ c #586397",
+"^$ c #576496",
+"/$ c #576499",
+"($ c #576497",
+"_$ c #5A6497",
+":$ c #5A6599",
+"<$ c #5A659B",
+"[$ c #5A6598",
+"}$ c #586599",
+"|$ c #586498",
+"1$ c #576297",
+"2$ c #535E92",
+"3$ c #525D92",
+"4$ c #4F5992",
+"5$ c #44528C",
+"6$ c #3F4C85",
+"7$ c #384282",
+"8$ c #4D568F",
+"9$ c #656C9D",
+"0$ c #767DA9",
+"a$ c #7F85AE",
+"b$ c #8087AF",
+"c$ c #8086AF",
+"d$ c #8489B0",
+"e$ c #848AB0",
+"f$ c #848BB0",
+"g$ c #848BAE",
+"h$ c #858BB3",
+"i$ c #868DAF",
+"j$ c #888EB0",
+"k$ c #8B91B2",
+"l$ c #8B91B0",
+"m$ c #8B91B3",
+"n$ c #8D94B6",
+"o$ c #8B92B6",
+"p$ c #8C93B8",
+"q$ c #8B93B6",
+"r$ c #8D95B8",
+"s$ c #8D95B9",
+"t$ c #8D96B7",
+"u$ c #8D95B7",
+"v$ c #8F97BB",
+"w$ c #8D95B6",
+"x$ c #8E96BA",
+"y$ c #8D96B6",
+"z$ c #9197BC",
+"A$ c #9198B8",
+"B$ c #9097BA",
+"C$ c #9199BE",
+"D$ c #9198BE",
+"E$ c #9097BB",
+"F$ c #8F97BA",
+"G$ c #8E97B9",
+"H$ c #8B94B8",
+"I$ c #8991B7",
+"J$ c #8088B0",
+"K$ c #7079A5",
+"L$ c #596497",
+"M$ c #434D87",
+"N$ c #33407D",
+"O$ c #6972A1",
+"P$ c #9398BB",
+"Q$ c #ABAFC9",
+"R$ c #B7BAD0",
+"S$ c #B9BDD2",
+"T$ c #BBBED3",
+"U$ c #BBBED4",
+"V$ c #BBBFD3",
+"W$ c #BCBFD4",
+"X$ c #BDBFD6",
+"Y$ c #BCBFD5",
+"Z$ c #BEC1D5",
+"`$ c #BEC2D6",
+" % c #BEC2D5",
+".% c #BFC3D6",
+"+% c #BFC3D7",
+"@% c #C0C3D8",
+"#% c #C0C4D7",
+"$% c #C1C5D8",
+"%% c #C1C5D9",
+"&% c #C2C6D9",
+"*% c #C1C6D9",
+"=% c #C2C6D8",
+"-% c #C1C6D8",
+";% c #C3C7D9",
+">% c #C2C7D9",
+",% c #C1C7D9",
+"'% c #C2C7D8",
+")% c #C3C7DB",
+"!% c #C3C7DA",
+"~% c #BFC5D8",
+"{% c #BDC1D7",
+"]% c #B2B8D0",
+"^% c #9DA3C2",
+"/% c #757EA8",
+"(% c #3A4882",
+"_% c #2B357B",
+":% c #4B538C",
+"<% c #787FA8",
+"[% c #A6ABC7",
+"}% c #C0C3D6",
+"|% c #CBCEDE",
+"1% c #CED0DF",
+"2% c #CDD0DF",
+"3% c #CFD2E0",
+"4% c #D0D2E0",
+"5% c #D0D2E1",
+"6% c #D0D3E1",
+"7% c #D0D3E0",
+"8% c #D2D3E0",
+"9% c #D2D4E1",
+"0% c #D2D5E3",
+"a% c #D3D5E3",
+"b% c #D3D6E4",
+"c% c #D3D6E3",
+"d% c #D3D7E4",
+"e% c #D4D7E5",
+"f% c #D3D7E3",
+"g% c #D4D8E4",
+"h% c #D5D8E5",
+"i% c #D5D8E4",
+"j% c #D5D8E6",
+"k% c #D0D4E2",
+"l% c #C6CADC",
+"m% c #B0B5CD",
+"n% c #848CB3",
+"o% c #596599",
+"p% c #3D4A83",
+"q% c #35427E",
+"r% c #2A347A",
+"s% c #424B86",
+"t% c #696F9E",
+"u% c #9397BA",
+"v% c #AAAEC8",
+"w% c #B6B9CF",
+"x% c #B9BCD1",
+"y% c #BBBED2",
+"z% c #BBBFD2",
+"A% c #BCBFD6",
+"B% c #BDBFD5",
+"C% c #BDC0D6",
+"D% c #BDC1D5",
+"E% c #BFC2D8",
+"F% c #BFC3D8",
+"G% c #C0C4D8",
+"H% c #C2C7DB",
+"I% c #C3C8DB",
+"J% c #C3C9DB",
+"K% c #C2C5DA",
+"L% c #B4B9D0",
+"M% c #9EA4C3",
+"N% c #7680AC",
+"O% c #546195",
+"P% c #3D4B85",
+"Q% c #384583",
+"R% c #323F7C",
+"S% c #323D7D",
+"T% c #495189",
+"U% c #616999",
+"V% c #747AA4",
+"W% c #7C82AA",
+"X% c #7E85AC",
+"Y% c #7F85AC",
+"Z% c #8488AF",
+"`% c #848AAE",
+" & c #848BAD",
+".& c #858BAE",
+"+& c #858DB4",
+"@& c #868DB0",
+"#& c #868DB2",
+"$& c #8990B2",
+"%& c #8991B4",
+"&& c #8B92B8",
+"*& c #8D93B6",
+"=& c #8D94B7",
+"-& c #8D92B9",
+";& c #8D96BA",
+">& c #8F96B8",
+",& c #8D96B8",
+"'& c #9197BE",
+")& c #9197BB",
+"!& c #9199BB",
+"~& c #929ABD",
+"{& c #929CBE",
+"]& c #939DBE",
+"^& c #929ABC",
+"/& c #929BBE",
+"(& c #949DBE",
+"_& c #929ABE",
+":& c #8C95B8",
+"<& c #858EB5",
+"[& c #737EAA",
+"}& c #5D699D",
+"|& c #48538D",
+"1& c #3A4886",
+"2& c #394786",
+"3& c #2C3677",
+"4& c #363D7B",
+"5& c #3B4580",
+"6& c #3F4984",
+"7& c #3F4884",
+"8& c #414A84",
+"9& c #454E86",
+"0& c #455087",
+"a& c #49508B",
+"b& c #495190",
+"c& c #49538B",
+"d& c #495390",
+"e& c #4B558C",
+"f& c #505A92",
+"g& c #515A96",
+"h& c #515C8F",
+"i& c #525D96",
+"j& c #536096",
+"k& c #576095",
+"l& c #57649A",
+"m& c #59659A",
+"n& c #5A659C",
+"o& c #5B6799",
+"p& c #5C689D",
+"q& c #5B679D",
+"r& c #5B689A",
+"s& c #5E699F",
+"t& c #5F6A9F",
+"u& c #5F6C9F",
+"v& c #606E9D",
+"w& c #606D9D",
+"x& c #616CA3",
+"y& c #606C9D",
+"z& c #606CA4",
+"A& c #606DA0",
+"B& c #5F6B9E",
+"C& c #5E6A9D",
+"D& c #5A689D",
+"E& c #59669B",
+"F& c #556198",
+"G& c #4E5C94",
+"H& c #485690",
+"I& c #3E4B89",
+"J& c #3B4885",
+"K& c #384685",
+"L& c #2A3477",
+"M& c #2A3677",
+"N& c #283670",
+"O& c #303E80",
+"P& c #303C80",
+"Q& c #353F81",
+"R& c #374383",
+"S& c #384384",
+"T& c #3A4788",
+"U& c #3A4A89",
+"V& c #3C4A88",
+"W& c #3D4C8C",
+"X& c #3F4D8C",
+"Y& c #404F8E",
+"Z& c #42508D",
+"`& c #41508D",
+" * c #435190",
+".* c #425290",
+"+* c #43528C",
+"@* c #43548F",
+"#* c #445494",
+"$* c #44548C",
+"%* c #445293",
+"&* c #445391",
+"** c #435090",
+"=* c #42518E",
+"-* c #41508E",
+";* c #404E8C",
+">* c #3F4D8A",
+",* c #3A4885",
+"'* c #374581",
+")* c #232C71",
+"!* c #242F76",
+"~* c #252F73",
+"{* c #253176",
+"]* c #293673",
+"^* c #2A3678",
+"/* c #2E3C7C",
+"(* c #313E79",
+"_* c #313C81",
+":* c #324084",
+"<* c #344082",
+"[* c #374382",
+"}* c #374786",
+"|* c #3B478C",
+"1* c #3C4B8C",
+"2* c #3F4C8C",
+"3* c #3E4E8E",
+"4* c #404F90",
+"5* c #414F8C",
+"6* c #425090",
+"7* c #455391",
+"8* c #475694",
+"9* c #445493",
+"0* c #455394",
+"a* c #424F8C",
+"b* c #465494",
+"c* c #46588F",
+"d* c #45568F",
+"e* c #455491",
+"f* c #445390",
+"g* c #43528E",
+"h* c #35417C",
+"i* c #212D71",
+"j* c #222D71",
+"k* c #242E71",
+"l* c #253173",
+"m* c #283179",
+"n* c #273476",
+"o* c #2D397C",
+"p* c #303C77",
+"q* c #34407F",
+"r* c #374484",
+"s* c #384489",
+"t* c #3A478B",
+"u* c #3A4684",
+"v* c #3B4B8C",
+"w* c #404E90",
+"x* c #435290",
+"y* c #42538D",
+"z* c #455494",
+"A* c #455593",
+"B* c #44558D",
+"C* c #465690",
+"D* c #475793",
+"E* c #485495",
+"F* c #475594",
+"G* c #465592",
+"H* c #41508C",
+"I* c #3C4A89",
+"J* c #202C71",
+"K* c #222E72",
+"L* c #2D3979",
+"M* c #364082",
+"N* c #344484",
+"O* c #364483",
+"P* c #384688",
+"Q* c #3D498D",
+"R* c #3E4E8C",
+"S* c #435191",
+"T* c #435391",
+"U* c #465491",
+"V* c #485795",
+"W* c #475496",
+"X* c #485894",
+"Y* c #46568B",
+"Z* c #495A92",
+"`* c #495996",
+" = c #495992",
+".= c #414F8A",
+"+= c #3E4C88",
+"@= c #1F2B6E",
+"#= c #222C70",
+"$= c #252E73",
+"%= c #263279",
+"&= c #2B3777",
+"*= c #2D3879",
+"== c #2F3C78",
+"-= c #324080",
+";= c #364287",
+">= c #384481",
+",= c #3E4D8C",
+"'= c #3E4B8D",
+")= c #424F8F",
+"!= c #425292",
+"~= c #435291",
+"{= c #45528D",
+"]= c #465594",
+"^= c #43548C",
+"/= c #475991",
+"(= c #4A5A99",
+"_= c #485791",
+":= c #485593",
+"<= c #4B5B9A",
+"[= c #4C5B98",
+"}= c #4A5A95",
+"|= c #495894",
+"1= c #404E8A",
+"2= c #3E4D89",
+"3= c #394680",
+"4= c #1F2A6D",
+"5= c #1F286D",
+"6= c #232E70",
+"7= c #232D71",
+"8= c #253072",
+"9= c #263172",
+"0= c #293675",
+"a= c #2B3879",
+"b= c #313F83",
+"c= c #384888",
+"d= c #3B498C",
+"e= c #404E8D",
+"f= c #42508E",
+"g= c #435292",
+"h= c #455492",
+"i= c #465695",
+"j= c #475691",
+"k= c #48568F",
+"l= c #47578F",
+"m= c #495993",
+"n= c #48568C",
+"o= c #4C5C9C",
+"p= c #4C5D9C",
+"q= c #4D5E98",
+"r= c #333E78",
+"s= c #1E296E",
+"t= c #1E2A6D",
+"u= c #222D70",
+"v= c #253171",
+"w= c #283276",
+"x= c #283476",
+"y= c #2A3773",
+"z= c #323F7F",
+"A= c #384285",
+"B= c #384684",
+"C= c #3F4B87",
+"D= c #46518C",
+"E= c #4D598E",
+"F= c #495493",
+"G= c #43538C",
+"H= c #414E92",
+"I= c #405090",
+"J= c #44528F",
+"K= c #45558F",
+"L= c #4A5898",
+"M= c #485A92",
+"N= c #4A599C",
+"O= c #4A5891",
+"P= c #4B5A95",
+"Q= c #4B5B96",
+"R= c #4D5D97",
+"S= c #4E5F98",
+"T= c #505E99",
+"U= c #4F5E9D",
+"V= c #4C5D98",
+"W= c #485893",
+"X= c #455390",
+"Y= c #212B6F",
+"Z= c #232E6D",
+"`= c #253074",
+" - c #293674",
+".- c #2D387A",
+"+- c #344280",
+"@- c #46528D",
+"#- c #5B669F",
+"$- c #737DAC",
+"%- c #7B86B1",
+"&- c #747DAD",
+"*- c #495791",
+"=- c #414E8C",
+"-- c #445291",
+";- c #465593",
+">- c #46568E",
+",- c #485A91",
+"'- c #485897",
+")- c #4A578D",
+"!- c #4B5C95",
+"~- c #4B5A93",
+"{- c #4E5E99",
+"]- c #4E5E97",
+"^- c #4D5D98",
+"/- c #4F5F9C",
+"(- c #4C5C97",
+"_- c #475692",
+":- c #3A4883",
+"<- c #1E276C",
+"[- c #202B6E",
+"}- c #1F2B70",
+"|- c #242E70",
+"1- c #273370",
+"2- c #293573",
+"3- c #2C387C",
+"4- c #2C397A",
+"5- c #2D3A7A",
+"6- c #3C4886",
+"7- c #596597",
+"8- c #8990B4",
+"9- c #ADB3CE",
+"0- c #BDC1D6",
+"a- c #AEB4CE",
+"b- c #8A92B8",
+"c- c #606C9F",
+"d- c #46548F",
+"e- c #465694",
+"f- c #465691",
+"g- c #475697",
+"h- c #4A5895",
+"i- c #4A5B94",
+"j- c #4C5B97",
+"k- c #4C5A92",
+"l- c #4F5F9D",
+"m- c #4F609A",
+"n- c #52639E",
+"o- c #4D5E9C",
+"p- c #4A5991",
+"q- c #4F5A94",
+"r- c #1D286C",
+"s- c #1D276C",
+"t- c #212B6D",
+"u- c #212E6E",
+"v- c #232F73",
+"w- c #283470",
+"x- c #2A3575",
+"y- c #2C377A",
+"z- c #2B3876",
+"A- c #2E3B76",
+"B- c #434D8D",
+"C- c #707BA9",
+"D- c #ADB3CC",
+"E- c #D8DAE6",
+"F- c #E3E6EE",
+"G- c #D8DAE7",
+"H- c #B0B5CE",
+"I- c #7580AB",
+"J- c #445492",
+"K- c #465791",
+"L- c #495899",
+"M- c #47578E",
+"N- c #4B5995",
+"O- c #4C588F",
+"P- c #4B5A92",
+"Q- c #4F5E93",
+"R- c #50619D",
+"S- c #51629D",
+"T- c #4B5A8D",
+"U- c #4A5A9A",
+"V- c #4E5E94",
+"W- c #4A5994",
+"X- c #495693",
+"Y- c #455490",
+"Z- c #1C276A",
+"`- c #1F296D",
+" ; c #202B6B",
+".; c #242F72",
+"+; c #25326D",
+"@; c #2C3976",
+"#; c #434F89",
+"$; c #7982AC",
+"%; c #BCC0D6",
+"&; c #EDEFF3",
+"*; c #7D87B1",
+"=; c #4F5D97",
+"-; c #445491",
+";; c #475492",
+">; c #475695",
+",; c #495995",
+"'; c #485895",
+"); c #4F5F9B",
+"!; c #4F6098",
+"~; c #506099",
+"{; c #4C598E",
+"]; c #4B5C97",
+"^; c #4A5A9B",
+"/; c #4A5A94",
+"(; c #3E4B85",
+"_; c #1D2768",
+":; c #1F296C",
+"<; c #232F72",
+"[; c #25306D",
+"}; c #293576",
+"|; c #2A3774",
+"1; c #2D3977",
+"2; c #303B80",
+"3; c #424A85",
+"4; c #6F78A5",
+"5; c #ADB2CC",
+"6; c #ADB3CD",
+"7; c #757EAB",
+"8; c #4A5892",
+"9; c #43518F",
+"0; c #46558D",
+"a; c #4A5993",
+"b; c #4A5B95",
+"c; c #4D5A90",
+"d; c #4E5E9B",
+"e; c #4E5F9B",
+"f; c #4F5F9A",
+"g; c #4E5B8F",
+"h; c #4F609C",
+"i; c #1C2769",
+"j; c #20296D",
+"k; c #212C6F",
+"l; c #222C6D",
+"m; c #23306F",
+"n; c #263275",
+"o; c #293578",
+"p; c #384580",
+"q; c #586398",
+"r; c #8790B4",
+"s; c #8991B6",
+"t; c #5E6B9F",
+"u; c #44528A",
+"v; c #40508D",
+"w; c #43508F",
+"x; c #43528F",
+"y; c #475495",
+"z; c #4A5793",
+"A; c #4B5991",
+"B; c #495891",
+"C; c #4C5B95",
+"D; c #4D5B90",
+"E; c #4D5A8F",
+"F; c #4F5E9A",
+"G; c #4D5E96",
+"H; c #49588A",
+"I; c #4A5A8D",
+"J; c #46528C",
+"K; c #1D266A",
+"L; c #1B2667",
+"M; c #212C6D",
+"N; c #212C6C",
+"O; c #263174",
+"P; c #283374",
+"Q; c #293671",
+"R; c #33407F",
+"S; c #424C86",
+"T; c #737CA9",
+"U; c #7D87AF",
+"V; c #747EAB",
+"W; c #5D6A9D",
+"X; c #4A558E",
+"Y; c #3F4E8C",
+"Z; c #41518F",
+"`; c #43538F",
+" > c #475792",
+".> c #475791",
+"+> c #495998",
+"@> c #4B5998",
+"#> c #4C5C95",
+"$> c #4C5A93",
+"%> c #4D5D99",
+"&> c #4A568A",
+"*> c #45548F",
+"=> c #1D286B",
+"-> c #1E2968",
+";> c #202A6D",
+">> c #283371",
+",> c #27336F",
+"'> c #2F3C7B",
+")> c #323E7D",
+"!> c #334081",
+"~> c #4B5993",
+"{> c #495690",
+"]> c #414F86",
+"^> c #3F4C89",
+"/> c #404D8C",
+"(> c #425091",
+"_> c #44528D",
+":> c #45548D",
+"<> c #475690",
+"[> c #48578F",
+"}> c #495588",
+"|> c #4C5A98",
+"1> c #4A568B",
+"2> c #4C5A96",
+"3> c #1C2768",
+"4> c #1B2767",
+"5> c #1B2665",
+"6> c #1F2B6D",
+"7> c #222D6F",
+"8> c #232F6E",
+"9> c #273373",
+"0> c #2E3A7B",
+"a> c #3A4888",
+"b> c #3E4C8B",
+"c> c #3B4B87",
+"d> c #3B4A8A",
+"e> c #3D4B88",
+"f> c #3F4E8B",
+"g> c #404E8B",
+"h> c #42518C",
+"i> c #455493",
+"j> c #475795",
+"k> c #485793",
+"l> c #48558B",
+"m> c #4A5992",
+"n> c #485794",
+"o> c #4A5694",
+"p> c #1E266B",
+"q> c #1D2668",
+"r> c #1E2869",
+"s> c #1C2867",
+"t> c #1E2A69",
+"u> c #222E6D",
+"v> c #263173",
+"w> c #2D3A77",
+"x> c #394684",
+"y> c #3A4A84",
+"z> c #3E4A8C",
+"A> c #3B4B88",
+"B> c #3D4987",
+"C> c #3C4B89",
+"D> c #3D4C8B",
+"E> c #40508C",
+"F> c #44548E",
+"G> c #44538F",
+"H> c #485592",
+"I> c #485792",
+"J> c #46568C",
+"K> c #42528C",
+"L> c #1A2665",
+"M> c #1E276B",
+"N> c #222C6F",
+"O> c #263271",
+"P> c #2A3574",
+"Q> c #364684",
+"R> c #3C4884",
+"S> c #3B4987",
+"T> c #3D4A87",
+"U> c #3D4A89",
+"V> c #3E4D8B",
+"W> c #42508C",
+"X> c #44528B",
+"Y> c #44538E",
+"Z> c #46548E",
+"`> c #465493",
+" , c #475593",
+"., c #475490",
+"+, c #4A5794",
+"@, c #424E8C",
+"#, c #3C477A",
+"$, c #1A2467",
+"%, c #1D2969",
+"&, c #1C2868",
+"*, c #202C6C",
+"=, c #232F6F",
+"-, c #243075",
+";, c #2E3B7C",
+">, c #2F3A7E",
+",, c #333F7C",
+"', c #3E4A84",
+"), c #3B4A88",
+"!, c #3F4D88",
+"~, c #404F8C",
+"{, c #42508F",
+"], c #44518C",
+"^, c #445490",
+"/, c #485693",
+"(, c #465284",
+"_, c #1B2464",
+":, c #1C266A",
+"<, c #1E276D",
+"[, c #202A6C",
+"}, c #1F2B6A",
+"|, c #25316F",
+"1, c #2C367D",
+"2, c #2E3A74",
+"3, c #2F3B7A",
+"4, c #303F7C",
+"5, c #324283",
+"6, c #3B4889",
+"7, c #3D4A88",
+"8, c #404F8A",
+"9, c #44528E",
+"0, c #475794",
+"a, c #465294",
+"b, c #3A4475",
+"c, c #182059",
+"d, c #1A2462",
+"e, c #1D2869",
+"f, c #1F296A",
+"g, c #212A6D",
+"h, c #252F6F",
+"i, c #263272",
+"j, c #283275",
+"k, c #2A3675",
+"l, c #2E3A77",
+"m, c #3B4887",
+"n, c #3C4A87",
+"o, c #3E4C89",
+"p, c #3F4C88",
+"q, c #42528F",
+"r, c #45558C",
+"s, c #1B2565",
+"t, c #25306F",
+"u, c #283373",
+"v, c #2D3A78",
+"w, c #3C4987",
+"x, c #3E4B88",
+"y, c #3E4C8A",
+"z, c #3E4E89",
+"A, c #3F4E8A",
+"B, c #414E89",
+"C, c #42518D",
+"D, c #414F8B",
+"E, c #445190",
+"F, c #42528D",
+"G, c #42518B",
+"H, c #3C467F",
+"I, c #1C2664",
+"J, c #1F2A6B",
+"K, c #242F6F",
+"L, c #3F4D89",
+"M, c #3F4F8A",
+"N, c #40508B",
+"O, c #1D2765",
+"P, c #3B4988",
+"Q, c #3C4A86",
+"R, c #3C4B87",
+"S, c #404F8B",
+"T, c #3D4B87",
+"U, c #3D4C88",
+"V, c #3F4C87",
+" . + @ @ # $ % & * = - ; ",
+" > , ' ) ! ~ { ] ^ / ( % _ : < [ } | 1 1 ",
+" 2 3 4 5 ' ) ! ~ { ] ^ / ( % _ : < [ 6 7 | | 8 1 ",
+" 9 0 0 a 3 4 b ' ) ! ~ { ] c / ( d _ : < [ 6 7 | e f f 8 g 1 ",
+" h h i 0 a 3 j b ' ) ! ~ { ] c / ( d _ : * [ 6 k | e f 8 8 8 l m ",
+" n o p i 0 q a 3 j b ' ) ! r { ] c s t d _ : * [ 6 | | e f 8 8 l l l g 1 ",
+" u o p h i 0 q a 4 5 b ' v ! r { ] # s % d _ w x } 6 | | e f 8 8 l l y z m m ",
+" A u u o p h i 0 a B 4 5 b ' ! ~ r C ^ # D % E _ < x 6 7 | | f 8 8 8 l F G G H I m J ",
+" K u u o o p i 0 q a 3 j b ' ) ! ~ { ] ^ L D M E _ < x 6 k | e f 8 8 l y G G N G H g m J ",
+" n u u u o p h i 0 q a 3 j b ' v ! ~ { ] c / ( d _ : * [ 6 k | e f 8 O P Q G Q Q G Q H g m J ",
+" K u u u o p h i 0 0 a 3 4 5 b R v ~ r S ^ # s % d _ w x T 6 | | e 8 8 G G Q N G Q N G N H m ; J ",
+" A u u U V W X Y Z ` ...+.@.#.$.%.! ~ { C ^ L D % E _ < x 6 k | | f G O Q G G G N G G Q G G H m ; J ",
+" u u u &.*.X =.Z -. ...+.;.>.,.$.'.! r { ^ ).D M E w * < [ 6 k | e O G G Q Q Q Q G Q G N G N N m m ; ",
+" u u o &.W X =.Y ` .!.~.+.@.{.$.%.].^./.(.% E L _.:.<.[.}.|.6 k 1.Q Q Q Q Q Q Q Q Q Q Q Q Q G G 2.3.3.1 ",
+" n o o o *.X Y Z -. .!.+.;.#.#.{.$.4.5.6.(.d 7.8.9.0.a.b.c.d.e.< f.g.f.f.f.f.Q g.g.f.g.f.f.g.f.Q Q - - - h.i. ",
+" o p p p j.Y Z ` .!.!.+.;.>.,.k.l.^.6.L % d # m.n.o.p.q.r.c.s.f.t.f.f.f.f.f.f.f.f.f.f.g.g.f.g.f.g.u.u.v.- h. ",
+" h p h h i Z -.` w. .+.+.;.,.,.{.x.{ y.z.A.% B.C.D.E.F.G.H.I.J.K.L.M.N.f.M.M.O.O.O.M.O.O.O.P.Q.M.f.P.R.R.u.u.u.h. ",
+" 9 h i i i 0 S.T. .!.+.+.;.>.,.$.U.V.W.X.Y.( Z.d `. +.+++@+G.#+$+%+&+*+=+O.O.-+M.O.O.O.O.O.M.-+M.O.O.;+>+,+'+R.R.u.1 ",
+" 0 i 0 0 0 q !.)+!++.;.@.#.{.{.~+V.5.{+]+^+( Z./+(+_+:+<+++<+:+[+}+|+1+).-+O.2+-+-+3+-+O.3+4+3+O.O.O.>+B.>+>+,+'+5+6+ ",
+" 0 0 q q a a )+7++.;.@.,.{.$.%.8+9+0++ a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+o+r+-+2+s+t+2+2+t+s+4+t+4+3+u+v+w+B.>+>+,+'+ ",
+" 2 a a a a B 3 +.x+;.,.{.,.$.'.y+z+A+B+*+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+s+s+X+s+Y+2+2+Z+q+`+`+u+ @w+w+.@,+h. ",
+" 3 3 3 3 4 4 j j 5 b ' {.%.%.'.'.A++@@@#@*+$@%@&@*@6.=@-@;@>@,@'@)@!@~@{@]@^@/@(@_@:@Y+Y+<@Y+2+[@}@|@|@|@|@1@`+u+ @w+B.,+ ",
+" 2@4 4 j j 5 5 b b b ' ' ) '.'.y+<@3@A+4@5@6@`+7@8@9@0@a@b@c@d@{@e@f@g@h@_@i@j@k@l@m@n@{@o@Y+o@Y+p@q@p@q@q@q@|@1@1@`+ @w+w+6+ ",
+" , 5 b b b b b ' ' R ) v ! '.y+<@Y+r@$@s@t@u@y.v@A+w@a@0@{@x@y@z@A@A@B@C@D@E@F@D@G@H@I@J@K@o@L@]@M@M@K@M@!@p@q@q@|@1@`+u+ @6+ ",
+" ' ' ' ' ' ' ' ) v v ! ! ~ <@Y+<@s+s@N@@@O@P@Q@o+R@S@T@U@V@W@(@X@Y@Z@`@`@ #.#+#@###$#%#&#*#, X@X@X@X@X@X@, M@M@p@q@|@=#-#`+;# ",
+" ) ) ) ) ) v ! ! ! ~ ~ r { Y+s+t+s+>#,#'#)#A+!#~#R@{#]#^#j@j@C@H@/#/#(#_#:#.#<#[#}#|#1#2#3#4#D@*#*#D@D@D@X@, , M@!@p@q@5#-#`+ ",
+". ! ! ! ! ! ! ~ ~ ~ r { { C ] s+4+O.6#7#8#P@9#0#a#b#/@c#d#e#f#4#g#.#h#i#$#j#k#l#m#n#o#p#q#r#s#t#u#_#*#*#*#D@D@X@, M@M@p@q@5#v#;#",
+"+ ~ ~ ~ ~ r r r { { S C ] ^ @ -+-+-+4+w#x#r+y#z#A#W@]#g@B#C#D#E#F#G#H#I#J#K#L#M#N#O#P#Q#R#S#r#k#s#s#t#u#_#*#*#D@D@X@, M@T#q@5#U#",
+"@ { { { { { { C ] V#W#X#Y#Z#Z#`# $ $`#.$+$@$#$$$%$&$*$=$-$;$>$,$'$)$!$~${$]$^$/$($]$_$:$<$[$}$|$1$1$2$3$4$5$6$*#*#D@X@, M@T#q@v#",
+"@ ] ] ] ] ] ] ^ 7$8$9$0$a$b$c$d$d$e$f$g$h$i$j$k$l$m$n$o$p$q$r$r$s$t$u$v$w$x$y$z$A$B$C$C$D$D$z$E$F$G$H$I$J$K$L$M$_#*#N$D@, M@T#5#",
+"# ^ ^ c c c # { Z#O$P$Q$R$S$S$T$T$U$V$W$X$Y$Z$`$ %.%+%+%@%#%$%%%$%&%*%=%-%;%;%>%,%'%)%)%;%)%!%;%>%&%~%{%]%^%/%2$(%_#*#N$D@X@M@q@",
+"$ / / / / s s _%:%<%[%}%|%1%2%3%4%5%4%6%7%8%9%9%0%a%b%a%c%b%b%b%c%d%e%f%e%e%g%h%i%j%h%j%j%j%h%h%h%h%d%k%l%m%n%o%p%s#_#q%N$D@, T#",
+"% ( ( ( ( t % r%s%t%u%v%w%x%x%T$y%z%W$A%B%C%D%`$`$+%@%E%.%F%G%G%%%*%H%>%;%>%>%)%;%I%J%J%J%J%I%)%!%!%K%+%L%M%N%O%P%Q%s#_#q%N$R%M@",
+"& % % d d d d E S%T%U%V%W%X%Y%Z%`%e$ &.&+&@&#&$&%&&&*&&&=&-&;&>&,&'&)&D$D$!&~&{&]&^&/&(&]&(&{&{&/&_&v$:&<&[&}&|&1&2&Q%s#_#q%N$, ",
+"* _ _ _ _ _ _ _ _ 3&4&5&6&7&8&9&0&a&b&c&d&e&e&f&&$g&h&i&j&>$k&l&m&n&o&p&q&r&s&t&u&v&w&x&y&z&A&B&C&C&D&E&F&G&H&I&2 J&K&Q%s#_#q%R%",
+"= : : : : : w < < * x x [ }.e.L.O.O.4@L&2+M&N&O&d#P&d#Q&G#R&S&T&U&V&W&X&Y&Y&Z&`& *.*+*@*#*$*%*&*****=*-*-*;*>*I&I&2 ,*K&Q%'*q%R%",
+"- < < < * * x x x [ T 6 6 }.e.)*!*~*{*q+]*^*/*P&(*_*:*<*[*}*L#|*1*2*3*4*5*6*`&7*8*9*0*a*b*c*d*e*f*f*f*g*=*-*;*>*I&I&2 ,*Q%Q%_#h*",
+"; [ [ [ [ [ } 6 6 6 6 k T < i*j*k*~*l*m*n*M&o*c@c@p*q*:#r*s*t*K#u*v*X&w* *x* *y*z*A*B*C*D*E*F*G*G*G*e*f*x***Z&H*>*I&I*J&,*Q%'*h*",
+" } 6 6 6 6 6 7 k k | g.T = J*t.K*. O.v+u@1@L*c@O&O&M*N*O*P*|*>.Q*V&R*R*;*Z&S*T*U*V*W*X*Y*Z*`* =8*8*8*G*e*f*g*Z&.=>*+=2 J&Q%'* ",
+" | 7 7 k | | | Q G }.k @=6 6 #=7.$=%=v+4@&=&=*===-=N*;=P*>=u*u*>.,='=)=!=~={=]=^=/=(=_=X*:=<=[=}=|=|=8*G*e*f*g*H*1=2=+=J&,*3= ",
+" 1 | | | | | | e e 4=5=6 6 T j*6=7=7=8=9=^ 0=a=_.b=M*O*P*c=d=,.@.R*R*e=f=g=z*h=i=j=k=l=m=n=o=p=q=}=K |=8*G*e*f*=*H*>*+=2 J&r= ",
+" 1 | e e e e f f s=f t=e }.T = < u=7.v=O.w=x=y=c@z=N*A=B=C=D=E=F=G=H=I=6*J=]=K=L=M=N=O=P=Q=R=S=T=U=V=K W=8*G*X=g*H*1=I&2 J&r= ",
+" 8 f f f f 8 8 f Q G = e k = Y=j*Z=`=L ,# -&=.-b#+-O*@-#-$-%-&-u&*-=-.*--f*;->-,-'-)-!-~-{-S=]-^-/-(-K W=_-e*f*=*.=2=+=:- ",
+" 1 f 8 8 8 8 f f <-O 8 O f [-}-u=|-8=D+1-2-3-4-5-A@6-7-8-9-0-a-b-c-d- *--e-f-g-h-h-i-j-k-l-m-n-q=o-p-q-|=W=G*f*g*.=2=+=h* ",
+" 8 8 8 8 8 r-s-8 5=<-8 t=k t-u-v-t O.w-x-y-z-A-d#B-C-D-E-F-G-H-I-p-f=--J-K-L-M-N-O-P-q=Q-R-S-S-T-U-V-W-X-_-Y-g*H*1=+= ",
+" g 8 l l l s-l 8 Z-s-8 5=`- ;u=.;>++;4@A+0#@;n+(@#;$;%;F-&;F-0-*;=;=*x*-;;;>;,;';N-o=]-);!;~;{;!;];^;/;/;_-Y-g*H*1=(; ",
+" 1 l l l l l l <-s-l 8 _;:;= #=<;[;B.};M&|;1;2;l@3;4;5;E-F-G-6;7;8;f=9;z*0;j=*-a;b;c;d;e;f;g;{-h;P-^;/;/;_-Y-g*H*1=3= ",
+" m l l I l l m g i;8 8 j;k;l;'+m;n;o;2+2+n+e@X@p;q;r;D-0-a-s;t;u;v;w;x;9*y;_-z;A;B;C;D;E;F;G;H;}=I;e-J;_-Y-g*H*(; ",
+" g I I I I K;F l L;g - M;N;Z=O;P;)#Q;0#{#U@k@R;S;o%T;U;V;W;X;Y;Y&Z;`;f* >>;.>+>@>#>$>%>%>&>#>/;^;/;/;_-*>g*1= ",
+" 1 I I I I I m I l =>e ->;>6=8=>>,>};=@R@'>)>!>/#P%@-~>{>]>I*^>/>Y&(>_>:>:><>[>}>~>|>(-1>2>n W-/;/;e-G*X=g*3= ",
+" L;I 3.3.I K;3>4>5>8 6>7>j*8>8=9>'#L*1;0>z@z=F#K&a>I*b>c>d>e>f>g>h>S*--i>y;j=j>k>_=l>h-m>n>}=/;o>e-Y-g*.= ",
+" N N p>m q>K;I K;r>s>t>u>,+v>w=`+^*w>n+d#B@:#x>u*y>z>A>B>C>D>Y;E>H*F>G>F>G*H>I>k=';_-X*X*W-/;/;J>J>K> ",
+" J H G 5>L>M>L;3.<-:;6 N>7>>+O>P>7@)@n+b#z=F@Q>u*y>>.R>S>T>U>V>X&5*f=W>&*X>Y>Z>`>j= ,.,X-+,e-e-!+@,#, ",
+" J ; 5>$,F m i;%,&,*,7>=,d+-,u+1@M&;,>,,,~+u*,.y>',D>),V&e>e>!,/>~,H*{,],^,J-`;-;-;/,8* =J>J>(,#, ",
+" J ; _,L;; :,l <,[,},N>|,+ q+M&1,2,3,4,5,Q>{.u*u*',6,),C>7,e>+=g>8,E>H*W>h>x;f*9,0,J-o>a,K>b, ",
+" c,; d,; 3>e,f,[,g,7>h,i,j,k,=@l,e@D@*#t#Q%K&1&2 7,m,n,o,o,o,V>p,g>g>v;`&q,J=f*G=r,J>K>#, ",
+" J s,1 3>3.2. ;R.'+t,9=u,k,&=v,c#D@*#_#t#Q%K&1&2 w,1&n,x,y,>*z,A,B,C,C,D,x;C,E,F,G,H, ",
+" 1 I,3>2.J,u.R.K,9=9>P>&=!@M@X@D@*#_#s#Q%2&J&2 w,S>n,T>o,L,A,A,M,M,D,N,C,g*.= ",
+" i.O,f, ; ;R.K,w+9>x-|@p@M@, X@N$*#_#s#Q%K&,*2 P,Q,R,n,T>x,x,L,A,1=S,1=3= ",
+" h.u.5+,+.@w+ @`+=#q@p@M@, D@N$q%_#s#Q%K&,*J&2 T,n,7,U,U,+=+=V,(; ",
+" 1 6+'+,+B.w+u+-#5#q@T#M@, D@N$q%_#s#Q%Q%,*J&J&2 2 +=+=+=(;3= ",
+" h.,+w+ @`+-#5#q@T#M@X@D@N$q%_#'*Q%Q%Q%,*J&J&:-h* ",
+" 6+6+;#`+v#5#q@T#M@, R%N$q%q%_#'*'*3=r=r= ",
+" ;#U#v#5#q@T#M@, R%R%h*h* "};
diff --git a/arts/builder/pics/Synth_EMPTY.xpm b/arts/builder/pics/Synth_EMPTY.xpm
new file mode 100644
index 00000000..0fc95945
--- /dev/null
+++ b/arts/builder/pics/Synth_EMPTY.xpm
@@ -0,0 +1,1119 @@
+/* XPM */
+static char * Synth_EMPTY_xpm[] = {
+"64 64 1052 2",
+" c None",
+". c #253073",
+"+ c #273276",
+"@ c #293378",
+"# c #283278",
+"$ c #263077",
+"% c #252F75",
+"& c #232E74",
+"* c #212B71",
+"= c #202A6E",
+"- c #1E296A",
+"; c #1C2667",
+"> c #2B3671",
+", c #313D7B",
+"' c #384288",
+") c #353F87",
+"! c #323D83",
+"~ c #2F3A80",
+"{ c #2D377D",
+"] c #2A357B",
+"^ c #29347A",
+"/ c #273177",
+"( c #253076",
+"_ c #232D72",
+": c #222C72",
+"< c #212C71",
+"[ c #202B70",
+"} c #202A70",
+"| c #1F296E",
+"1 c #1B2463",
+"2 c #3C4988",
+"3 c #434D95",
+"4 c #414C93",
+"5 c #3D488D",
+"6 c #202A6F",
+"7 c #1F2A6F",
+"8 c #1E286C",
+"9 c #37437E",
+"0 c #4F59A0",
+"a c #485399",
+"b c #3B458D",
+"c c #283379",
+"d c #242E74",
+"e c #1E296D",
+"f c #1E286D",
+"g c #1C2669",
+"h c #5862A8",
+"i c #555FA6",
+"j c #3F4B90",
+"k c #1F2A6E",
+"l c #1D276B",
+"m c #1C2668",
+"n c #4B5A97",
+"o c #616CB3",
+"p c #5C67AF",
+"q c #4B579B",
+"r c #2E397F",
+"s c #263177",
+"t c #253075",
+"u c #6872B4",
+"v c #343F84",
+"w c #222C71",
+"x c #212B70",
+"y c #1B2666",
+"z c #1B2366",
+"A c #45538B",
+"B c #445194",
+"C c #2B367B",
+"D c #263076",
+"E c #232E73",
+"F c #1D266B",
+"G c #1E266C",
+"H c #1A2264",
+"I c #1D276A",
+"J c #171F57",
+"K c #4A5996",
+"L c #273277",
+"M c #242F74",
+"N c #1A2664",
+"O c #1E296C",
+"P c #1D296B",
+"Q c #1E2A6C",
+"R c #354186",
+"S c #2C377B",
+"T c #202B6F",
+"U c #6672BC",
+"V c #666EB4",
+"W c #5E6AB4",
+"X c #5A66AC",
+"Y c #565EA4",
+"Z c #525EA4",
+"` c #4E5AA2",
+" . c #4A569C",
+".. c #465296",
+"+. c #424E94",
+"@. c #3E4A8E",
+"#. c #3E468C",
+"$. c #36428C",
+"%. c #363E84",
+"&. c #626EB4",
+"*. c #5E66AC",
+"=. c #5662AB",
+"-. c #525AA4",
+";. c #424A94",
+">. c #3A4A8C",
+",. c #3A468C",
+"'. c #323E84",
+"). c #273278",
+"!. c #4A529C",
+"~. c #464E93",
+"{. c #3A428C",
+"]. c #313983",
+"^. c #2D387E",
+"/. c #2A3479",
+"(. c #263176",
+"_. c #222D72",
+":. c #212A6F",
+"<. c #1F2B6F",
+"[. c #212A6E",
+"}. c #1E286A",
+"|. c #1D2769",
+"1. c #303B81",
+"2. c #2C367E",
+"3. c #293479",
+"4. c #232E72",
+"5. c #222D71",
+"6. c #212D72",
+"7. c #222E74",
+"8. c #222A6F",
+"9. c #1E2868",
+"0. c #1A235E",
+"a. c #5A62AC",
+"b. c #35418B",
+"c. c #2F3B80",
+"d. c #232D73",
+"e. c #222D73",
+"f. c #222B70",
+"g. c #212B6C",
+"h. c #20296C",
+"i. c #4E569C",
+"j. c #323A80",
+"k. c #29357A",
+"l. c #283178",
+"m. c #263075",
+"n. c #263171",
+"o. c #232F70",
+"p. c #222E73",
+"q. c #233070",
+"r. c #24306D",
+"s. c #232E70",
+"t. c #242F70",
+"u. c #252E6F",
+"v. c #242E73",
+"w. c #262E73",
+"x. c #262F73",
+"y. c #263273",
+"z. c #222E6C",
+"A. c #223264",
+"B. c #222D6E",
+"C. c #4E5AA4",
+"D. c #4A5A9C",
+"E. c #303C81",
+"F. c #2D397E",
+"G. c #2C357D",
+"H. c #273378",
+"I. c #263276",
+"J. c #252F76",
+"K. c #253070",
+"L. c #242F73",
+"M. c #243071",
+"N. c #24306F",
+"O. c #243073",
+"P. c #253177",
+"Q. c #26326E",
+"R. c #263277",
+"S. c #263078",
+"T. c #26327C",
+"U. c #252D72",
+"V. c #253071",
+"W. c #242F6E",
+"X. c #232E6E",
+"Y. c #46529C",
+"Z. c #425294",
+"`. c #354182",
+" + c #2B357D",
+".+ c #273178",
+"++ c #263175",
+"@+ c #262F74",
+"#+ c #273073",
+"$+ c #263272",
+"%+ c #25306E",
+"&+ c #273173",
+"*+ c #26336C",
+"=+ c #283273",
+"-+ c #2A3674",
+";+ c #26366C",
+">+ c #2A3274",
+",+ c #232E6C",
+"'+ c #212B69",
+")+ c #464E94",
+"!+ c #2F3B81",
+"~+ c #2D3679",
+"{+ c #2B357C",
+"]+ c #273272",
+"^+ c #273274",
+"/+ c #273076",
+"(+ c #243074",
+"_+ c #283274",
+":+ c #263174",
+"<+ c #283374",
+"[+ c #293373",
+"}+ c #283575",
+"|+ c #293577",
+"1+ c #293376",
+"2+ c #293575",
+"3+ c #2B3779",
+"4+ c #28337A",
+"5+ c #293574",
+"6+ c #2B377D",
+"7+ c #2A367C",
+"8+ c #2A327C",
+"9+ c #293474",
+"0+ c #273273",
+"a+ c #273271",
+"b+ c #3E4A94",
+"c+ c #323A84",
+"d+ c #2E3A7F",
+"e+ c #2A3679",
+"f+ c #2A3579",
+"g+ c #263470",
+"h+ c #263274",
+"i+ c #273377",
+"j+ c #273371",
+"k+ c #27346F",
+"l+ c #293475",
+"m+ c #2A357A",
+"n+ c #2A3675",
+"o+ c #2C3878",
+"p+ c #2D3978",
+"q+ c #2D3777",
+"r+ c #2D3976",
+"s+ c #2E397B",
+"t+ c #2D3775",
+"u+ c #2B3873",
+"v+ c #2F3B77",
+"w+ c #30397E",
+"x+ c #2F3775",
+"y+ c #2A386E",
+"z+ c #2E3A7D",
+"A+ c #293579",
+"B+ c #293473",
+"C+ c #263170",
+"D+ c #2A357C",
+"E+ c #2A3379",
+"F+ c #293278",
+"G+ c #273279",
+"H+ c #2A3378",
+"I+ c #283377",
+"J+ c #283378",
+"K+ c #2C3779",
+"L+ c #2B3679",
+"M+ c #2B3877",
+"N+ c #2E397C",
+"O+ c #2D397C",
+"P+ c #2D397A",
+"Q+ c #2E3B7A",
+"R+ c #2E387D",
+"S+ c #2F3B7D",
+"T+ c #2E3C7A",
+"U+ c #2F387D",
+"V+ c #2F3B7F",
+"W+ c #313D7F",
+"X+ c #303E7E",
+"Y+ c #2F387C",
+"Z+ c #2E367C",
+"`+ c #2C3877",
+" @ c #2C3777",
+".@ c #2A3676",
+"+@ c #2B3571",
+"@@ c #2B3478",
+"#@ c #283477",
+"$@ c #2A3375",
+"%@ c #2A3474",
+"&@ c #2A3576",
+"*@ c #2B3676",
+"=@ c #2C3778",
+"-@ c #2C387A",
+";@ c #2C397B",
+">@ c #2E387B",
+",@ c #2E3A7C",
+"'@ c #2E3B7B",
+")@ c #2F3C7C",
+"!@ c #2F3D7C",
+"~@ c #303D7D",
+"{@ c #303D7E",
+"]@ c #313F7E",
+"^@ c #313E80",
+"/@ c #313D7D",
+"(@ c #313E7F",
+"_@ c #324081",
+":@ c #323E81",
+"<@ c #2E3E7C",
+"[@ c #2D3A79",
+"}@ c #283677",
+"|@ c #2A347C",
+"1@ c #263372",
+"2@ c #283479",
+"3@ c #283578",
+"4@ c #2B377B",
+"5@ c #2F3C7D",
+"6@ c #2F3C7E",
+"7@ c #303C7D",
+"8@ c #313E7E",
+"9@ c #323E7E",
+"0@ c #333F7F",
+"a@ c #323F7E",
+"b@ c #333F80",
+"c@ c #344081",
+"d@ c #333F7E",
+"e@ c #33417F",
+"f@ c #354183",
+"g@ c #34407E",
+"h@ c #2F3B7E",
+"i@ c #303980",
+"j@ c #2F3C7A",
+"k@ c #2A3279",
+"l@ c #293478",
+"m@ c #2B357A",
+"n@ c #2B3579",
+"o@ c #2D397B",
+"p@ c #2E3B7D",
+"q@ c #2F3B7B",
+"r@ c #2F3D7F",
+"s@ c #303D7F",
+"t@ c #313E7D",
+"u@ c #313F81",
+"v@ c #334082",
+"w@ c #334080",
+"x@ c #344183",
+"y@ c #354284",
+"z@ c #35417E",
+"A@ c #344284",
+"B@ c #364386",
+"C@ c #364385",
+"D@ c #364282",
+"E@ c #354383",
+"F@ c #344180",
+"G@ c #2B3776",
+"H@ c #2B3675",
+"I@ c #283370",
+"J@ c #29337C",
+"K@ c #273375",
+"L@ c #293477",
+"M@ c #283474",
+"N@ c #2C377C",
+"O@ c #2C3875",
+"P@ c #2E3A7E",
+"Q@ c #303C7F",
+"R@ c #303D7C",
+"S@ c #344181",
+"T@ c #344281",
+"U@ c #354280",
+"V@ c #344282",
+"W@ c #34427F",
+"X@ c #374280",
+"Y@ c #364482",
+"Z@ c #374487",
+"`@ c #374582",
+" # c #374586",
+".# c #384485",
+"+# c #344080",
+"@# c #2D3876",
+"## c #26327B",
+"$# c #273477",
+"%# c #2A3475",
+"&# c #2A3775",
+"*# c #2C3879",
+"=# c #2E3A78",
+"-# c #2F3B7C",
+";# c #303C7B",
+"># c #323E7F",
+",# c #323F80",
+"'# c #333F81",
+")# c #334180",
+"!# c #364283",
+"~# c #364382",
+"{# c #374385",
+"]# c #384584",
+"^# c #354482",
+"/# c #384588",
+"(# c #384587",
+"_# c #394585",
+":# c #394587",
+"<# c #394686",
+"[# c #394687",
+"}# c #374483",
+"|# c #354382",
+"1# c #354282",
+"2# c #2B3775",
+"3# c #2A337C",
+"4# c #283570",
+"5# c #2D377C",
+"6# c #2D3A7C",
+"7# c #323F81",
+"8# c #344182",
+"9# c #334181",
+"0# c #344382",
+"a# c #354281",
+"b# c #364484",
+"c# c #364583",
+"d# c #374482",
+"e# c #384585",
+"f# c #374684",
+"g# c #374685",
+"h# c #374480",
+"i# c #3A4686",
+"j# c #394885",
+"k# c #3A4988",
+"l# c #3A4A8A",
+"m# c #3A4989",
+"n# c #3A4786",
+"o# c #2F3B78",
+"p# c #2B3674",
+"q# c #283473",
+"r# c #2C387D",
+"s# c #2A3778",
+"t# c #2E3B7C",
+"u# c #313D80",
+"v# c #33407E",
+"w# c #364483",
+"x# c #394684",
+"y# c #374686",
+"z# c #374682",
+"A# c #3A4785",
+"B# c #394884",
+"C# c #394888",
+"D# c #3C4886",
+"E# c #3C4A8B",
+"F# c #3C4A87",
+"G# c #3A4887",
+"H# c #394685",
+"I# c #384685",
+"J# c #384583",
+"K# c #2A337B",
+"L# c #2E3976",
+"M# c #333D79",
+"N# c #313D77",
+"O# c #333E7B",
+"P# c #374380",
+"Q# c #364485",
+"R# c #374683",
+"S# c #374583",
+"T# c #3A4889",
+"U# c #364582",
+"V# c #384682",
+"W# c #3C498A",
+"X# c #3C4B85",
+"Y# c #3B4A87",
+"Z# c #3D4C8C",
+"`# c #3E4B8C",
+" $ c #3D4B8C",
+".$ c #3B4988",
+"+$ c #394786",
+"@$ c #33407D",
+"#$ c #27347B",
+"$$ c #2D3A7F",
+"%$ c #2F3A7B",
+"&$ c #364383",
+"*$ c #384684",
+"=$ c #3B4887",
+"-$ c #3A4885",
+";$ c #384883",
+">$ c #3D4A88",
+",$ c #3D4C8A",
+"'$ c #3C4B88",
+")$ c #394986",
+"!$ c #3C4A84",
+"~$ c #3F4C8C",
+"{$ c #3F4E8E",
+"]$ c #3E4E8A",
+"^$ c #3E4E8D",
+"/$ c #3E4D8B",
+"($ c #3D4B8A",
+"_$ c #3A4888",
+":$ c #3A4787",
+"<$ c #263279",
+"[$ c #283276",
+"}$ c #283478",
+"|$ c #2A3771",
+"1$ c #33407F",
+"2$ c #344385",
+"3$ c #344084",
+"4$ c #374585",
+"5$ c #384488",
+"6$ c #374587",
+"7$ c #394788",
+"8$ c #3B488C",
+"9$ c #394784",
+"0$ c #3B488A",
+"a$ c #3B498A",
+"b$ c #3B4B88",
+"c$ c #3F4D89",
+"d$ c #3E4D88",
+"e$ c #3F4F89",
+"f$ c #414E91",
+"g$ c #404F8E",
+"h$ c #404E8D",
+"i$ c #404D8C",
+"j$ c #3E4C8B",
+"k$ c #3C4A89",
+"l$ c #3A4886",
+"m$ c #35427E",
+"n$ c #283277",
+"o$ c #27327C",
+"p$ c #2C387B",
+"q$ c #364083",
+"r$ c #333C83",
+"s$ c #34407F",
+"t$ c #354385",
+"u$ c #394789",
+"v$ c #3C4A8C",
+"w$ c #3B4986",
+"x$ c #3E4B8A",
+"y$ c #3C4B89",
+"z$ c #3F4C88",
+"A$ c #404F8D",
+"B$ c #41518D",
+"C$ c #42518C",
+"D$ c #42508F",
+"E$ c #41518E",
+"F$ c #404F90",
+"G$ c #3F4E8C",
+"H$ c #323F7C",
+"I$ c #26346F",
+"J$ c #2F3B79",
+"K$ c #334084",
+"L$ c #384186",
+"M$ c #374687",
+"N$ c #3A4685",
+"O$ c #3C498C",
+"P$ c #3E4C88",
+"Q$ c #3F4E8B",
+"R$ c #41508E",
+"S$ c #425190",
+"T$ c #414E8A",
+"U$ c #43538D",
+"V$ c #42528E",
+"W$ c #435190",
+"X$ c #41508C",
+"Y$ c #404E8C",
+"Z$ c #3E4D8C",
+"`$ c #232D71",
+" % c #242E71",
+".% c #283077",
+"+% c #28327C",
+"@% c #28347C",
+"#% c #2A3678",
+"$% c #323E80",
+"%% c #323C84",
+"&% c #323F7B",
+"*% c #344384",
+"=% c #384483",
+"-% c #384889",
+";% c #3F4D8E",
+">% c #3E4C8D",
+",% c #3E4D8A",
+"'% c #414E90",
+")% c #425090",
+"!% c #425290",
+"~% c #44548E",
+"{% c #44538E",
+"]% c #455294",
+"^% c #43528E",
+"/% c #445295",
+"(% c #435391",
+"_% c #42518F",
+":% c #3F4D8A",
+"<% c #3E4B89",
+"[% c #3B4885",
+"}% c #2A3477",
+"|% c #2A3677",
+"1% c #283670",
+"2% c #303E80",
+"3% c #303C80",
+"4% c #353F81",
+"5% c #374383",
+"6% c #384384",
+"7% c #3A4788",
+"8% c #3A4A89",
+"9% c #3C4A88",
+"0% c #3F4D8C",
+"a% c #42508D",
+"b% c #41508D",
+"c% c #43528C",
+"d% c #43548F",
+"e% c #445494",
+"f% c #44548C",
+"g% c #445293",
+"h% c #445391",
+"i% c #435090",
+"j% c #42518E",
+"k% c #374581",
+"l% c #232C71",
+"m% c #242F76",
+"n% c #252F73",
+"o% c #253176",
+"p% c #293673",
+"q% c #2E3C7C",
+"r% c #313E79",
+"s% c #313C81",
+"t% c #324084",
+"u% c #344082",
+"v% c #374382",
+"w% c #374786",
+"x% c #3B478C",
+"y% c #3C4B8C",
+"z% c #3E4E8E",
+"A% c #414F8C",
+"B% c #455391",
+"C% c #475694",
+"D% c #445493",
+"E% c #455394",
+"F% c #424F8C",
+"G% c #465494",
+"H% c #46588F",
+"I% c #45568F",
+"J% c #455491",
+"K% c #445390",
+"L% c #35417C",
+"M% c #212D71",
+"N% c #253173",
+"O% c #283179",
+"P% c #273476",
+"Q% c #303C77",
+"R% c #374484",
+"S% c #384489",
+"T% c #3A478B",
+"U% c #3A4684",
+"V% c #3B4B8C",
+"W% c #404E90",
+"X% c #435290",
+"Y% c #42538D",
+"Z% c #455494",
+"`% c #455593",
+" & c #44558D",
+".& c #465690",
+"+& c #475793",
+"@& c #485495",
+"#& c #475594",
+"$& c #465592",
+"%& c #202C71",
+"&& c #222E72",
+"*& c #2D3979",
+"=& c #364082",
+"-& c #344484",
+";& c #384688",
+">& c #3D498D",
+",& c #3E4E8C",
+"'& c #435191",
+")& c #465491",
+"!& c #485795",
+"~& c #475496",
+"{& c #485894",
+"]& c #46568B",
+"^& c #495A92",
+"/& c #495996",
+"(& c #495992",
+"_& c #414F8A",
+":& c #1F2B6E",
+"<& c #222C70",
+"[& c #252E73",
+"}& c #2B3777",
+"|& c #2D3879",
+"1& c #2F3C78",
+"2& c #324080",
+"3& c #364287",
+"4& c #384481",
+"5& c #3E4B8D",
+"6& c #424F8F",
+"7& c #425292",
+"8& c #435291",
+"9& c #45528D",
+"0& c #465594",
+"a& c #43548C",
+"b& c #475991",
+"c& c #4A5A99",
+"d& c #485791",
+"e& c #485593",
+"f& c #4B5B9A",
+"g& c #4C5B98",
+"h& c #4A5A95",
+"i& c #495894",
+"j& c #404E8A",
+"k& c #3E4D89",
+"l& c #394680",
+"m& c #1F2A6D",
+"n& c #1F286D",
+"o& c #253072",
+"p& c #263172",
+"q& c #293675",
+"r& c #2B3879",
+"s& c #303A7B",
+"t& c #313F83",
+"u& c #384888",
+"v& c #3B498C",
+"w& c #42508E",
+"x& c #435292",
+"y& c #455492",
+"z& c #465695",
+"A& c #475691",
+"B& c #48568F",
+"C& c #47578F",
+"D& c #495993",
+"E& c #48568C",
+"F& c #4C5C9C",
+"G& c #4C5D9C",
+"H& c #4D5E98",
+"I& c #333E78",
+"J& c #1E296E",
+"K& c #1E2A6D",
+"L& c #222D70",
+"M& c #253171",
+"N& c #283476",
+"O& c #2A3773",
+"P& c #323F7F",
+"Q& c #384285",
+"R& c #3A4687",
+"S& c #3E4A84",
+"T& c #414E92",
+"U& c #405090",
+"V& c #44528F",
+"W& c #45558F",
+"X& c #4A5898",
+"Y& c #485A92",
+"Z& c #4A599C",
+"`& c #4A5891",
+" * c #4B5A95",
+".* c #4B5B96",
+"+* c #4D5D97",
+"@* c #4E5F98",
+"#* c #505E99",
+"$* c #4F5E9D",
+"%* c #4C5D98",
+"&* c #485893",
+"** c #455390",
+"=* c #212B6F",
+"-* c #232E6D",
+";* c #253074",
+">* c #293674",
+",* c #2D387A",
+"'* c #344280",
+")* c #3A478C",
+"!* c #3B4A8D",
+"~* c #414E8C",
+"{* c #445291",
+"]* c #465593",
+"^* c #46568E",
+"/* c #485A91",
+"(* c #485897",
+"_* c #4A578D",
+":* c #4B5C95",
+"<* c #4B5A93",
+"[* c #4E5E99",
+"}* c #4E5E97",
+"|* c #4D5D98",
+"1* c #4F5F9C",
+"2* c #4C5C97",
+"3* c #475692",
+"4* c #3A4883",
+"5* c #1E276C",
+"6* c #202B6E",
+"7* c #1F2B70",
+"8* c #242E70",
+"9* c #273370",
+"0* c #293573",
+"a* c #2C387C",
+"b* c #2C397A",
+"c* c #2D3A7A",
+"d* c #374386",
+"e* c #3C4885",
+"f* c #3C4A8A",
+"g* c #404F8C",
+"h* c #414F8F",
+"i* c #465694",
+"j* c #465691",
+"k* c #475697",
+"l* c #4A5895",
+"m* c #4A5B94",
+"n* c #4C5B97",
+"o* c #4C5A92",
+"p* c #4F5F9D",
+"q* c #4F609A",
+"r* c #52639E",
+"s* c #4D5E9C",
+"t* c #4A5991",
+"u* c #4F5A94",
+"v* c #1D286C",
+"w* c #1D276C",
+"x* c #212B6D",
+"y* c #212E6E",
+"z* c #232F73",
+"A* c #283470",
+"B* c #2A3575",
+"C* c #2C377A",
+"D* c #2B3876",
+"E* c #2E3B76",
+"F* c #354388",
+"G* c #384787",
+"H* c #404D8B",
+"I* c #445492",
+"J* c #465791",
+"K* c #495899",
+"L* c #47578E",
+"M* c #4B5995",
+"N* c #4C588F",
+"O* c #4B5A92",
+"P* c #4F5E93",
+"Q* c #50619D",
+"R* c #51629D",
+"S* c #4B5A8D",
+"T* c #4A5A9A",
+"U* c #4E5E94",
+"V* c #4A5994",
+"W* c #495693",
+"X* c #455490",
+"Y* c #1C276A",
+"Z* c #1F296D",
+"`* c #202B6B",
+" = c #242F72",
+".= c #25326D",
+"+= c #2C3976",
+"@= c #2E3A7A",
+"#= c #3E4C8C",
+"$= c #445491",
+"%= c #475492",
+"&= c #475695",
+"*= c #495995",
+"== c #485895",
+"-= c #4F5F9B",
+";= c #4F6098",
+">= c #506099",
+",= c #4C598E",
+"'= c #4B5C97",
+")= c #4A5A9B",
+"!= c #4A5A94",
+"~= c #3E4B85",
+"{= c #1D2768",
+"]= c #1F296C",
+"^= c #232F72",
+"/= c #25306D",
+"(= c #293576",
+"_= c #2A3774",
+":= c #2D3977",
+"<= c #303B80",
+"[= c #3D4B89",
+"}= c #43518F",
+"|= c #46558D",
+"1= c #495791",
+"2= c #4A5993",
+"3= c #4A5B95",
+"4= c #4D5A90",
+"5= c #4E5E9B",
+"6= c #4E5F9B",
+"7= c #4F5F9A",
+"8= c #4E5B8F",
+"9= c #4F609C",
+"0= c #1C2769",
+"a= c #20296D",
+"b= c #212C6F",
+"c= c #222C6D",
+"d= c #23306F",
+"e= c #263275",
+"f= c #293578",
+"g= c #364384",
+"h= c #40508D",
+"i= c #43508F",
+"j= c #43528F",
+"k= c #475495",
+"l= c #4A5793",
+"m= c #4B5991",
+"n= c #495891",
+"o= c #4C5B95",
+"p= c #4D5B90",
+"q= c #4D5A8F",
+"r= c #4F5E9A",
+"s= c #4D5E96",
+"t= c #49588A",
+"u= c #4A5A8D",
+"v= c #46528C",
+"w= c #1D266A",
+"x= c #1B2667",
+"y= c #212C6D",
+"z= c #212C6C",
+"A= c #293671",
+"B= c #3F4B89",
+"C= c #41518F",
+"D= c #43538F",
+"E= c #475792",
+"F= c #475791",
+"G= c #495998",
+"H= c #4B5998",
+"I= c #4C5C95",
+"J= c #4C5A93",
+"K= c #4D5D99",
+"L= c #4A568A",
+"M= c #45548F",
+"N= c #1D286B",
+"O= c #1E2968",
+"P= c #202A6D",
+"Q= c #283371",
+"R= c #27336F",
+"S= c #2F3C7B",
+"T= c #323E7D",
+"U= c #334081",
+"V= c #3C4A86",
+"W= c #3F4C89",
+"X= c #425091",
+"Y= c #44528D",
+"Z= c #45548D",
+"`= c #475690",
+" - c #48578F",
+".- c #495588",
+"+- c #4B5993",
+"@- c #4C5A98",
+"#- c #4A568B",
+"$- c #4C5A96",
+"%- c #1C2768",
+"&- c #1B2767",
+"*- c #1B2665",
+"=- c #1F2B6D",
+"-- c #222D6F",
+";- c #232F6E",
+">- c #273373",
+",- c #2E3A7B",
+"'- c #3B4B87",
+")- c #3B4A8A",
+"!- c #3D4B88",
+"~- c #404E8B",
+"{- c #455493",
+"]- c #475795",
+"^- c #485793",
+"/- c #48558B",
+"(- c #4A5992",
+"_- c #485794",
+":- c #4A5694",
+"<- c #1E266B",
+"[- c #1D2668",
+"}- c #1E2869",
+"|- c #1C2867",
+"1- c #1E2A69",
+"2- c #222E6D",
+"3- c #263173",
+"4- c #2D3A77",
+"5- c #3A4A84",
+"6- c #3E4A8C",
+"7- c #3D4987",
+"8- c #3D4C8B",
+"9- c #40508C",
+"0- c #44538F",
+"a- c #485592",
+"b- c #485792",
+"c- c #46568C",
+"d- c #42528C",
+"e- c #1A2665",
+"f- c #1E276B",
+"g- c #222C6F",
+"h- c #263271",
+"i- c #2A3574",
+"j- c #364684",
+"k- c #3C4884",
+"l- c #3B4987",
+"m- c #3D4A87",
+"n- c #3D4A89",
+"o- c #42508C",
+"p- c #44528B",
+"q- c #46548E",
+"r- c #465493",
+"s- c #475593",
+"t- c #475490",
+"u- c #4A5794",
+"v- c #424E8C",
+"w- c #3C477A",
+"x- c #1A2467",
+"y- c #1D2969",
+"z- c #1C2868",
+"A- c #202C6C",
+"B- c #232F6F",
+"C- c #243075",
+"D- c #2F3A7E",
+"E- c #333F7C",
+"F- c #3B4A88",
+"G- c #3F4D88",
+"H- c #44518C",
+"I- c #445490",
+"J- c #485693",
+"K- c #465284",
+"L- c #1B2464",
+"M- c #1C266A",
+"N- c #1E276D",
+"O- c #202A6C",
+"P- c #1F2B6A",
+"Q- c #25316F",
+"R- c #2C367D",
+"S- c #2E3A74",
+"T- c #2F3B7A",
+"U- c #303F7C",
+"V- c #324283",
+"W- c #3B4889",
+"X- c #404F8A",
+"Y- c #44528E",
+"Z- c #475794",
+"`- c #465294",
+" ; c #3A4475",
+".; c #182059",
+"+; c #1A2462",
+"@; c #1D2869",
+"#; c #1F296A",
+"$; c #212A6D",
+"%; c #252F6F",
+"&; c #283275",
+"*; c #2E3A77",
+"=; c #3E4C89",
+"-; c #42528F",
+";; c #43538C",
+">; c #45558C",
+",; c #1B2565",
+"'; c #25306F",
+"); c #283373",
+"!; c #2D3A78",
+"~; c #3C4987",
+"{; c #3E4B88",
+"]; c #3E4C8A",
+"^; c #3E4E89",
+"/; c #3F4E8A",
+"(; c #414E89",
+"_; c #42518D",
+":; c #414F8B",
+"<; c #445190",
+"[; c #42528D",
+"}; c #42518B",
+"|; c #3C467F",
+"1; c #1C2664",
+"2; c #1F2A6B",
+"3; c #242F6F",
+"4; c #3F4F8A",
+"5; c #40508B",
+"6; c #1D2765",
+"7; c #3C4B87",
+"8; c #404F8B",
+"9; c #3D4B87",
+"0; c #3D4C88",
+"a; c #3F4C87",
+" . + @ @ # $ % & * = - ; ",
+" > , ' ) ! ~ { ] ^ / ( % _ : < [ } | 1 1 ",
+" 2 3 4 5 ' ) ! ~ { ] ^ / ( % _ : < [ 6 7 | | 8 1 ",
+" 9 0 0 a 3 4 b ' ) ! ~ { ] c / ( d _ : < [ 6 7 | e f f 8 g 1 ",
+" h h i 0 a 3 j b ' ) ! ~ { ] c / ( d _ : * [ 6 k | e f 8 8 8 l m ",
+" n o p i 0 q a 3 j b ' ) ! r { ] c s t d _ : * [ 6 | | e f 8 8 l l l g 1 ",
+" u o p h i 0 q a 4 5 b ' v ! r { ] # s % d _ w x } 6 | | e f 8 8 l l y z m m ",
+" A u u o p h i 0 a B 4 5 b ' ! ~ r C ^ # D % E _ < x 6 7 | | f 8 8 8 l F G G H I m J ",
+" K u u o o p i 0 q a 3 j b ' ) ! ~ { ] ^ L D M E _ < x 6 k | e f 8 8 l y G G N G H g m J ",
+" n u u u o p h i 0 q a 3 j b ' v ! ~ { ] c / ( d _ : * [ 6 k | e f 8 O P Q G Q Q G Q H g m J ",
+" K u u u o p h i 0 0 a 3 4 5 b R v ~ r S ^ # s % d _ w x T 6 | | e 8 8 G G Q N G Q N G N H m ; J ",
+" A u u U V W X Y Z ` ...+.@.#.$.%.! ~ { C ^ L D % E _ < x 6 k | | f G O Q G G G N G G Q G G H m ; J ",
+" u u u &.*.X =.Z -. ...+.;.>.,.$.'.! r { ^ ).D M E w * < [ 6 k | e O G G Q Q Q Q G Q G N G N N m m ; ",
+" u u o &.W X =.Y ` .!.~.+.@.{.$.%.].^./.(.% E _.* < x 6 :.<.6 k [.Q Q Q Q Q Q Q Q Q Q Q Q Q G G }.|.|.1 ",
+" n o o o *.X Y Z -. .!.+.;.#.#.{.$.1.2.3.(.d 4._.< 5.:.< _.:.6.< 7.8.7.7.7.7.Q 8.8.7.8.7.7.8.7.Q Q - - - 9.0. ",
+" o p p p a.Y Z ` .!.!.+.;.>.,.b.c.^.3.L % d d.w e.f.w w w _.w 7.f.7.7.7.7.7.7.7.7.7.7.8.8.7.8.7.8.g.g.h.- 9. ",
+" h p h h i Z -.` i. .+.+.;.,.,.{.j.{ k.l.m.% n.o.p.q.r.s.p.t.u.7.v.w.x.7.w.w.y.y.y.w.y.y.y.z.A.w.7.z.B.B.g.g.g.9. ",
+" 9 h i i i 0 C.D. .!.+.+.;.>.,.$.E.F.G.H.I.( J.d E K.& L.M.N.O.P.Q.O.R.S.y.y.T.w.y.y.y.y.y.w.T.w.y.y.U.V.W.X.B.B.g.1 ",
+" 0 i 0 0 0 q !.Y.Z.+.;.@.#.{.{.`.F.2. +.+++( J.L.L.@+N.v.#+$+%+&+).*+=+).T.y.-+T.T.;+T.y.;+>+;+y.y.y.V.n.V.V.W.X.,+'+ ",
+" 0 0 q q a a Y.)++.;.@.,.{.$.%.!+~+{++ ]+^+/+(+K._+t :+<+[+}+|+1+2+3+4+5+3+6+T.-+7+8+-+-+8+7+>+8+>+;+9+0+a+n.V.V.W.X. ",
+" 2 a a a a B 3 +.b+;.,.{.,.$.'.c+d+e+f+R.g+h+i+j+k+l+m+n+-+o+S o+p+q+r+s+t+u+v+w+x+y+7+7+y+7+z+-+-+A+5+2+2+9+B+a+a+C+W.9. ",
+" 3 3 3 3 4 4 j j 5 b ' {.%.%.'.'.e+D+E+F+R.G+H+I+J+3.K+L+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+z+z+Z+z+-+`+o+ @ @ @ @.@2+9+B+a+n.W. ",
+" +@4 4 j j 5 5 b b b ' ' ) '.'.c+Z+@@e+#@$@%@2+&@*@=@-@;@>@,@'@S+)@!@~@{@X+]@^@/@(@_@:@S+<@z+<@z+[@p+[@p+p+p+ @.@.@2+B+a+a+'+ ",
+" , 5 b b b b b ' ' R ) v ! '.c+Z+z+}@G+|@1@2@k.3@e+4@;@-@S+5@6@7@8@8@9@0@a@b@c@a@d@e@f@g@h@<@i@T+j@j@h@j@Q+[@p+p+ @.@2+9+B+'+ ",
+" ' ' ' ' ' ' ' ) v v ! ! ~ Z+z+Z+7+|@k@E+l@m@n@3+o@N+p@q@r@s@W+t@u@v@w@w@x@y@z@A@B@C@D@E@F@, t@t@t@t@t@t@, j@j@[@p+ @G@H@2+I@ ",
+" ) ) ) ) ) v ! ! ! ~ ~ r { z+7+8+7+J@K@L@M@e+N@O@o@P@Q@R@^@^@0@e@S@S@T@U@V@y@W@X@Y@Z@`@ #.#+#a@F@F@a@a@a@t@, , j@Q+[@p+@#H@2+ ",
+". ! ! ! ! ! ! ~ ~ ~ r { { C ] 7+>+y.##$#%#m@&#*#=#-#V+;#>#,#'#+#)#y@!#~#C@{#]#^#/#(#_#:#<#[#}#|#1#U@F@F@F@a@a@t@, j@j@[@p+@#2#I@",
+"+ ~ ~ ~ ~ r r r { { S C ] ^ @ T.T.T.>+3#4#6+5#L+6#s@Q@~@7#8#9#0#a#b#c#d#e#f#g#h#i#j#k#l#m#n#[#]#}#}#|#1#U@F@F@a@a@t@, j@o#p+@#p#",
+"@ { { { { { { C ] ] ^ ^ c # L (.D D (.T.q#6+r#s#t#u#s@v#x@8#~#w#b#`@x#y#z#A#B#C#j#n#D#2 E#F#k#G#H#I#J#}#}#|#U@F@F@a@t@, j@o#p+2#",
+"@ ] ] ] ] ] ] ^ ^ c # L / (.D % % t (.y.K#p#L#M#N#O#P#9#y@V@Q#b# #R#S#T#U#[#V#W#X#Y#Z#Z#`# $W#.$G#+$+$I#J#J#}#|#U@F@@$a@, j@o#@#",
+"# ^ ^ c c c # # L / s D t % M d d % :+K@3##$p+$$%$a@8#8#&$Y@I#+$*$=$C#-$;$>$,$'$)$!$~${$]$^$/$($2 _$_$:$+$I#J#J#|#U@F@@$a@t@j@p+",
+"$ / / / / s s D D ( % % M v.E 7.w.<$[$}$|$L#[@o#Q@1$2$3$~#4$5$6$*$7$8$9$0$a$b$c$d${$e$f$g$h$i$j$($k$k$2 2 l$+$I#J#}#U@m$@$a@, o#",
+"% ( ( ( ( t % % M d d E _ _ _ 7.x.y.n$o$n@6+p$z+V+8#q$r$s$t$b#}#u$C#v$w$x$y$y$Z#z$A$B$C$D$E$F$G$/$j$j$($k$2 _$l$I#J#}#U@m$@$H$j@",
+"& % % d d d d E E _ _ _ : w _ d O.$ I$q#7+2#3+J$)@K$D@3$&$L$M$N$I#O$2 $ $P$Q$R$S$T$g$U$V$W$X$R$A$Y$Z$j$j$($k$2 l$+$J#}#U@m$@$, ",
+"* _ _ _ _ _ _ _ _ : w < < * `$ %O..%+%#@@%#%#%Q@$%%%&%K$*%~#=%-%a$O$P$;%>%,%'%)%!%~%{%]%^%/%(%_%R$R$R$Y$Z$:%j$<%2 [%I#J#}#U@m$H$",
+"= : : : : : w < < * x x [ :.6.v.y.y.#@}%-+|%1%2%>#3%>#4%b#5%6%7%8%9%Z#0%g$g$a%b%W$!%c%d%e%f%g%h%i%i%j%R$R$Y$:%<%<%2 -$I#J#k%m$H$",
+"- < < < * * x x x [ T 6 6 :.6.l%m%n%o%5+p%#%q%3%r%s%t%u%v%w%g#x%y%~$z%F$A%)%b%B%C%D%E%F%G%H%I%J%K%K%K%^%j%R$Y$:%<%<%2 -$J#J#U@L%",
+"; [ [ [ [ [ } 6 6 6 6 k T < M%5. %n%N%O%P%|%O+,@,@Q%s$V@R%S%T%f#U%V%0%W%W$X%W$Y%Z%`% &.&+&@&#&$&$&$&J%K%X%i%a%X$:%<%k$[%-$J#k%L%",
+" } 6 6 6 6 6 7 k k | 8.T = %&f.&&. y.0+2@.@*&,@2%2%=&-&w#;&x%>.>&9%,&,&Y$a%'&(%)&!&~&{&]&^&/&(&C%C%C%$&J%K%^%a%_&:%P$2 [%J#k% ",
+" | 7 7 k | | | Q G :.k :&6 6 <&4.[&<$0+#@}&}&|&1&2&-&3&;&4&U%U%>.Z$5&6&7&8&9&0&a&b&c&d&{&e&f&g&h&i&i&C%$&J%K%^%X$j&k&P$[%-$l& ",
+" 1 | | | | | | e e m&n&6 6 T 5.s.`$`$o&p&^ q&r&s&t&=&w#;&u&v&,.@.,&,&h$w&x&Z%y&z&A&B&C&D&E&F&G&H&h&K i&C%$&J%K%j%X$:%P$2 [%I& ",
+" 1 | e e e e f f J&f K&e :.T = < L&4.M&y.[$N&O&,@P&-&Q&*$R&:$S&@.,&T&U&)%V&0&W&X&Y&Z&`& *.*+*@*#*$*%*K &*C%$&**^%X$j&<%2 [%I& ",
+" 8 f f f f 8 8 f Q G = e k = =*5.-*;*L K@>*}&,*-#'*w#_$)*!*>.@.,&Z$~*!%{*K%]*^*/*(*_*:*<*[*@*}*|*1*2*K &*3*J%K%j%_&k&P$4* ",
+" 1 f 8 8 8 8 f f 5*O 8 O f 6*7*L&8*o&h+9*0*a*b*c*8@d*J#e*f*($j$/$g*h*W${*i*j*k*l*l*m*n*o*p*q*r*H&s*t*u*i&&*$&K%^%_&k&P$L% ",
+" 8 8 8 8 8 v*w*8 n&5*8 K&k x*y*z*t y.A*B*C*D*E*>#F*G*_$k$($Z$H*G$g*w&{*I*J*K*L*M*N*O*H&P*Q*R*R*S*T*U*V*W*3*X*^%X$j&P$ ",
+" g 8 l l l w*l 8 Y*w*8 n&Z*`*L& =V..=#@e+*#+=@=W+1$I#:$k$($Z$#=0%h$j%X%$=%=&=*===M*F&}*-=;=>=,=;='=)=!=!=3*X*^%X$j&~= ",
+" 1 l l l l l l 5*w*l 8 {=]== <&^=/=n.(=|%_=:=<=(@1$&$:$k$($Z$[=~$h$w&}=Z%|=A&1=2=3=4=5=6=7=8=[*9=O*)=!=!=3*X*^%X$j&l& ",
+" m l l I l l m g 0=8 8 a=b=c=X.d=e=f=-+-+@=)@t@v#g=+$2 ($j$y$Z#:%h=i=j=D%k=3*l=m=n=o=p=q=r=s=t=h&u=i*v=3*X*^%X$~= ",
+" g I I I I w=F l x=g - y=z=-*:+<+M@A=*#P@q@/@1$T@I#2 ($j$y$B=G$g$C=D=K%E=&=F=G=H=I=J=K=K=L=I=!=)=!=!=3*M=^%j& ",
+" 1 I I I I I m I l N=e O=P=s.o&Q=R=(=K+o@S=T=U=S@I#_$k$j$V=k$W=i$g$X=Y=Z=Z=`= -.-+-@-2*#-$-n V*!=!=i*$&**^%l& ",
+" x=I |.|.I w=%-&-*-8 =---5.;-o&>-L@*&:=,-7@P&a#I#_$k$j$'-)-!-Q$~-C$'&{*{-k=A&]-^-d&/-l*(-_-h&!=:-i*X*^%_& ",
+" N N <-m [-w=I w=}-|-1-2-W.3-[$2+#%4-@=>#9@V@x#U%5-6-b$7-y$8-G$9-X$~%0-~%$&a-b-B&==3*{&{&V*!=!=c-c-d- ",
+" J H G *-e-f-x=|.5*]=6 g---V.h-i-&@P+@=-#P&c@j-U%5->.k-l-m-n-/$0%A%w&o-h%p-{%q-r-A&s-t-W*u-i*i*Z.v-w- ",
+" J ; *-x-F m 0=y-z-A---B-(+C-9+.@|%t#D-E-`.U%,.5-S&8-F-9%!-!-G-i$g*X$D$H-I-I*D=$=$=J-C%(&c-c-K-w- ",
+" J ; L-x=; M-l N-O-P-g-Q-+ 5+|%R-S-T-U-V-j-{.U%U%S&W-F-y$>$!-P$~-X-9-X$o-C$j=K%Y-Z-I*:-`-d- ; ",
+" .;; +;; %-@;#;O-$;--%;$+&;n+K+*;)@a@F@|#J#I#l$2 >$=$F#=;=;=;/$z$~-~-h=b%-;V&K%;;>;c-d-w- ",
+" J ,;1 %-|.}.`*B.X.';p&);n+}&!;;#a@F@U@|#J#I#l$2 ~;l$F#{;];:%^;/;(;_;_;:;j=_;<;[;};|; ",
+" 1 1;%-}.2;g.B.3;p&>-i-}&Q+j@t@a@F@U@}#J#+$[%2 ~;l-F#m-=;c$/;/;4;4;:;5;_;^%_& ",
+" 0.6;#;`*`*B.3;a+>-B* @[@j@, t@@$F@U@}#J#I#-$2 .$V=7;F#m-{;{;c$/;j&8;j&l& ",
+" 9.g.,+W.C+a+B+2+G@p+[@j@, a@@$m$U@}#J#I#-$[%2 9;F#>$0;0;P$P$a;~= ",
+" 1 '+X.W.n.a+9+H@@#p+o#j@, a@@$m$U@}#J#J#-$[%[%2 2 P$P$P$~=l& ",
+" 9.W.a+B+2+H@@#p+o#j@t@a@@$m$U@k%J#J#J#-$[%[%4*L% ",
+" '+'+I@2+2#@#p+o#j@, H$@$m$m$U@k%k%l&I&I& ",
+" I@p#2#@#p+o#j@, H$H$L%L% "};
diff --git a/arts/builder/pics/Synth_ENVELOPE_ADSR.xpm b/arts/builder/pics/Synth_ENVELOPE_ADSR.xpm
new file mode 100644
index 00000000..4408f29d
--- /dev/null
+++ b/arts/builder/pics/Synth_ENVELOPE_ADSR.xpm
@@ -0,0 +1,318 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 247 2",
+/* colors */
+" c #54E523",
+" . c #364281",
+" X c #24306C",
+" o c #313E7C",
+" O c #303C7B",
+" + c #1E2A66",
+" @ c #2E3A79",
+" # c #505AA1",
+" $ c #1C2864",
+" % c #2C3877",
+" & c #4D589E",
+" * c #2A3675",
+" = c #293474",
+" - c #283473",
+" ; c #253070",
+" : c #334081",
+" > c #41607E",
+" , c #2E3A7C",
+" < c #1E2869",
+" 1 c #2B3679",
+" 2 c #2A3678",
+" 3 c #7C84AE",
+" 4 c #39448A",
+" 5 c #263074",
+" 6 c #232E71",
+" 7 c #303C81",
+" 8 c #202A6E",
+" 9 c #1E286C",
+" 0 c #414F8B",
+" q c #1D286B",
+" w c #2E387F",
+" e c #273278",
+" r c #1A235E",
+" t c #295252",
+" y c #384582",
+" u c #445391",
+" i c #313F7B",
+" p c #3E4D8B",
+" a c #3D4B8A",
+" s c #2D3977",
+" d c #3B4988",
+" f c #8C95BD",
+" g c #384585",
+" h c #55689E",
+" j c #858DB6",
+" k c #303D7D",
+" l c #1F2B69",
+" z c #2F3B7C",
+" x c #2B3778",
+" c c #45DA16",
+" v c #368640",
+" b c #295A44",
+" n c #333F83",
+" m c #313D81",
+" M c #43528C",
+" N c #1E296B",
+" B c #1D276A",
+" V c #3C9E35",
+" C c #2C3E72",
+" Z c #293379",
+" A c #2D6341",
+" S c #283378",
+" D c #263176",
+" F c #3A586F",
+" G c #252F75",
+" H c #242F74",
+" J c #41D015",
+" K c #232D73",
+" L c #3C4A88",
+" P c #4A5899",
+" I c #374483",
+" U c #354281",
+" Y c #33407F",
+" T c #409349",
+" R c #2E3A7A",
+" E c #1C2665",
+" W c #1B2464",
+" Q c #364285",
+" ! c #232E6F",
+" ~ c #323E81",
+" ^ c #434E95",
+" / c #212A6D",
+" ( c #303C7F",
+" ) c #3CBE16",
+" _ c #3E4A90",
+" ` c #2C387B",
+" ' c #1C2668",
+" ] c #1B2667",
+" [ c #293478",
+" { c #273276",
+" } c #394981",
+" | c #253074",
+". c #384580",
+".. c #263E61",
+".X c #37724D",
+".o c #37417F",
+".O c #222C71",
+".+ c #212C70",
+".@ c #202A6F",
+".# c #1F2A6E",
+".$ c #42518D",
+".% c #2E3A80",
+".& c #1E286D",
+".* c #1D286C",
+".= c #3E4D89",
+".- c #4E5D9C",
+".; c #3D4B88",
+".: c #3B4986",
+".> c #3A4785",
+"., c #384583",
+".< c #465594",
+".1 c #445192",
+".2 c #425190",
+".3 c #323F7D",
+".4 c #323D7D",
+".5 c #212B69",
+".6 c #2F3B7A",
+".7 c #4CD125",
+".8 c #3A4788",
+".9 c #4C5893",
+".0 c #273372",
+".q c None",
+".w c #263171",
+".e c #253666",
+".r c #222D6D",
+".t c #6E78A7",
+".y c #414D92",
+".u c #2F3B7D",
+".i c #1F296A",
+".p c #3F4B90",
+".a c #405287",
+".s c #2B3779",
+".d c #3B458C",
+".f c #283376",
+".g c #273375",
+".h c #374388",
+".j c #394680",
+".k c #364187",
+".l c #242F72",
+".z c #343F85",
+".x c #222B70",
+".c c #34427B",
+".v c #6670B6",
+".b c #1E296C",
+".n c #41508B",
+".m c #1D276B",
+".M c #404E8A",
+".N c #326747",
+".B c #3CAE22",
+".V c #3E4C88",
+".C c #2A357B",
+".Z c #3C4A86",
+".A c #44D219",
+".S c #465693",
+".D c #455492",
+".F c #33407D",
+".G c #42508F",
+".H c #404E8D",
+".J c #2B3A75",
+".K c #3C4889",
+".L c #2B3675",
+".P c #3A4887",
+".I c #384685",
+".U c #495699",
+".Y c #354282",
+".T c #25306F",
+".R c #36625B",
+".E c #43A739",
+".W c #5560A8",
+".Q c #344777",
+".! c #3DC215",
+".~ c #2D387A",
+".^ c #3B923B",
+"./ c #518F5E",
+".( c #384288",
+".) c #385274",
+"._ c #47529A",
+".` c #73A386",
+".' c #253072",
+".] c #475790",
+".[ c #232E70",
+".{ c #171F57",
+".} c #1F2A6C",
+".| c #6C75A7",
+"X c #424F8B",
+"X. c #2D387D",
+"XX c #1C2669",
+"Xo c #2C367C",
+"XO c #2B367B",
+"X+ c #283478",
+"X@ c #253075",
+"X# c #485794",
+"X$ c #45C023",
+"X% c #242E74",
+"X& c #232E73",
+"X* c #212C71",
+"X= c #34417D",
+"X- c #577192",
+"X; c #202A70",
+"X: c #1F2A6F",
+"X> c #3EB81C",
+"X, c #273370",
+"X< c #364582",
+"X1 c #364382",
+"X2 c #41CB18",
+"X3 c #5763A9",
+"X4 c #344180",
+"X5 c #303D7C",
+"X6 c #213260",
+"X7 c #2D3979",
+"X8 c #3D498C",
+"X9 c #3D478C",
+"X0 c #4D6295",
+"Xq c #2B3777",
+"Xw c #2A4962",
+"Xe c #293575",
+"Xr c #263172",
+"Xt c #42C71C",
+"Xy c #344183",
+"Xu c #737DA3",
+"Xi c #44548C",
+"Xp c #212B6D",
+"Xa c #4FDC22",
+"Xs c #1F296B",
+"Xd c #1E296A",
+"Xf c #2D397C",
+"Xg c #1D2769",
+"Xh c #1B2567",
+"Xj c #293578",
+"Xk c #4B5C96",
+"Xl c #4A5A95",
+"Xz c #273176",
+"Xx c #263175",
+"Xc c #465691",
+"Xv c #36427E",
+"Xb c #222D71",
+"Xn c #455490",
+"Xm c #212B70",
+"XM c #44528F",
+"XN c #33407B",
+"XB c #1F296E",
+"XV c #1E296D",
+"XC c #415782",
+"XZ c #2C377E",
+"XA c #4F5E9D",
+"XS c #5BF220",
+"XD c #3A8D3F",
+/* pixels */
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.qXr { [ Z e D HX&.O 8 N '.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.L.4.(.k n.%XZ.C Z eX@ H K.OX*X;X;XB W r.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.K ^.pX9 4.k n.%XZ.C Z eX@ H K.OX*X;.@X:XBXB 9 r.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.o # &._ ^.p.d 4.z m.%XZ.C S eX@X% K.OX*X;.@X:XBXV.&.& 9XX r.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.WX3 # &._ ^.p.d.(.z m.%XZ.C SXzX@X% K.OXmX;.@.#XBXV.& 9 9.*.m '.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q P.vX3.W # &._ ^ _.d.h.z m.%XZ.C S DX@X% K.OXmX;.@XBXBXV.& 9 9 q.m.mXX r.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.v.v.vX3.W # &._ ^ _.d.k.z 7 wXo.C e D GX% K.OXmX;.@XBXBXV.& 9 9.m.m.m B BXh.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.qX .v.v.vX3X3.W #._ ^.y _ 4.k n 7 wXo Z e D GX&XbX*Xm.@X:XBXB.& 9 9.*.m.m B B B B '.{.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.9.v.v.v.vX3.W # &._ ^.p.d 4.k ~.%X..C Z e D HX&XbX*Xm.@.#XBXV.& 9 9 q.m.m B B BXgXX '.{.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.9.v.v.v.vX3X3.W #.U._ ^ _.d.h.z m.%XZ.C SXzX@X% K.OXmX;.@.#XBXV.& 9 9 q.m.m B B BXgXXXX '.{.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.9.v.v.v.v.vX3.W # &._ ^.pX9 4.k n 7 wXo.C e D GX% K.OXm.@.@XBXBXV 9 9 q.m.m B B BXgXgXXXX ' E.{.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.qX .v.v.v.v.vX3.W # #.U._ ^ _.d.(.z ~.%X.Xo Z e D GX&XbX*Xm.@.#XBXB.& 9 9 9 9.m.m B B BXgXgXX ' ' E.{.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.v.v.v.v.vX3X3.W # &._ ^.p.d Q.z n 7 wXZ.C SXzX@ H K.OX*X;.@.#XBXBXVXV 9.b.b.b 9 9 9 9 < BXgXg ' ' E.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.v.v.v f fX3X3.W # &._ ^.pX8.8.o ~ m.%X.Xo Z e D GX& K.OXmX;.@.@ 8 8 8 8 8 8 8 8 8 8.}.}.bXs 9 < <XgXg W.q.q.q.q.q.q",
+".q.q.q.q.q P.v.v.v f f.W.W # &._ ^ ^X8.;.).R.Q z.~XZ.C Z { D HX& K.O.+.+.+.+.+.+.+.+.+.+.x.x.+XpXpXpXpXp.}.}Xs.iXd < r.q.q.q.q.q",
+".q.q.q.q.q.v.vX3X3X3.W # # &._._ ^.p dXC./.E.R C xXo Z e D GX%X& K KXbXbXbXbXb 6 6 6 6 6 6 6.[.[.[ ! !.r.rXpXpXp.}.} <.q.q.q.q.q",
+".q.q.q.q.WX3X3X3.W.W # # &._ ^ ^.pX9.>XC./.E.R C = Z ZXz D HX%X&X&X& H H H H H H H H.'.'.'.'.'.'.l.l.l.[.[ !.r.rXpXp.} <.q.q.q.q",
+".q.q.q.oX3.W.WX8 # f f.U._ ^ ^.pX9.d yXC./.7.X..X, SXz DX@X@ H H | | | | | 5 5 5 5 5 5 5XxXxXxXrXrXrXr.' ; ;.[ ! !.r.rXp $.q.q.q",
+".q.q.q # # # #.8 & f f._ ^.y _X9.d.( } F./.7 T.N...0 5Xz D DXxXxXxXxXx { { { {.f.f.f.f.f.f.fXe.g.g -.g.g.0XrXr ; ; ! !.r l.q.q.q",
+".q.q.q & & & &.(._ f j ^.p _.d 4.h Q.) F T .7.E bX,.w { { { { { { { S SX+ [ [XjXjXj 2 2 2 2XjXjXeXeXeXe - -.0.0Xr.w ; ! !.q.q.q",
+".q.q.K._._._._ n ^ j j _X9.d 4.kXy.j.R T.EXSXaX$.N.e.T { S S S SX+ [Xj 2 2 2 2 1.s.s.s.s.s.s.s x x xXq 2XeXeXe - -.0.w.w.T +.q.q",
+".q.q ^ ^ ^ ^ ^.y.p _X9.d 4.(.k.z.3.)./.7 XS .7 AX6 X { { [ [Xj 2 2 2.s.s.~ ` ` `XfXfXfXfXf.~.~.~X7.~ % xXqXqXeXe = -.0.w.T.q.q",
+".q.L.p.p.p _ _ _.d.d 4.(.k.z n m o.)./ XSXSXS V b...0.g 2 2.CXO.s ` `XfXfXf , , , z z z z z z R R R.~X7.~ % %.L *Xe -.0X,.5.q",
+".q.4X9.d.d.d.d.~ 4 3 3.z.z ~ 7.% @.) T XSXSXSXS.7.B bX, -XO.s ` ` `XfXf ,.u.u.u ( ( ( k k k k k kX5 z z z R @X7 % %.LXe = -.5.q",
+".q.( 4 4.(.h.k 1.k 3 3 ~ 7 7 wX. C.) T XSXSXSXS.7X$ A.e -XO `XfXf ,.u.u.u ( ( ( ~ ~ ~ ~ ~ ~ ~ ~ ~.3.3.4 kX5 z.6 @X7 %Xq.LXeX,.q",
+".q.k.k.z.z.z.z.f ~ 3 3.% wX.Xo `.QXw T Xa.7 A.eX,.s ` , ,.u ( ( ( ~ ~ ~ : : : : : : : : : : Y Y.3 o oX5 z R @X7 %.LXe.q",
+"Xr n n m m m 7.g.% 3 3X.XZXo 2 C.R v.E X$.^.^.^.BXa.^ b.. %X7.u.u ( m ~ ~ : : :XyXy.Y.Y.Y.Y.Y.Y.Y UX4X4 : Y.3.3 o O.6 @X7 %.L -",
+" {.%.%.%.%.% w wX.XZXoXo.C Z - C.X.7Xa XDXwXwXw.^XaX$.B b C s ( m ~ ~ : :Xy.Y Q Q Q Q I I I I IX1X1X1.Y UX4X4 Y.3 o o O.6 @ % *",
+" [XZXZXZXZXZXoXo.C.C.C Z S eX, C TXaXa TXwXwXw TXaXtX> A C C @.6 O i iXN.3XNX=X=XvXvXvXvXvX1 I g g., IX1X1 UX4 Y.3.3 o O.6 @.L",
+" Z.C.C.C.C.C.C.[ ZXuXu eXz DX,Xw T TXwXw.Q T.7XtX2 A.. C C C C C.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q. .I.I.>.I.I.,., IX1 UX4 Y.3 o O.6 %",
+" e Z Z S S S e.x eXuXu DX@ H.eXwXD .7X$.X C C C.R v.B.A V A A A A A.N.N.N.N.N.N.N.N.N.N.N.N F }.> d.P.8.>.I.,.,X1 .X4 Y.3 o O @",
+" D e e eXz D DXp DXuXu G H ;..XwXDXaX$.B bX, CX7.QXwXD c.AX2.!.!.!.!.!.! ) ) ) ) ) ) ) )X>.B vXC.Z L L d d.P.>.I., I .X4 Y.3 o.6",
+" HX@X@X@X@X@ G / HXuXuX&.[.e.R v.EXa.^ b.. - * ` CXwXD.A.A.A J J JX2X2X2X2X2X2X2X2X2X2X2XtXt T >XC a a a L d.P.>.I., I .Xv Y.3 O",
+"X& H HX%X%X%X%X&X& K KXb X.. v.7.7.A AX6 XXj 2 `.J.Q vX$.A c c c c c c c c c c c c c c c c.AXD F >.M p p a a L d.P.>., I .X4X= o",
+".O K K K K K KXbXb.O.OX*.r.. vXa.AXt A.eX,Xj `Xf @ i.R T T T T T T T T T T T T T T T TXD.B.A.E T.RXC.M.H p p a.; d.:.>., I .X= o",
+" 8.O.O.O.O.O.OXdX*.t.tXm l.. vXa.AXt A.eX,.s `Xf , k.Q.).) F F F F > > > > > > > > > > F T.AXtX$ T >.a.G.H.H p.=.; d.>.> yX1Xv.3",
+" NX*X*X*XmXmXm <Xm.t.t 8.eXwXD cXtX> b.eX,.sXf ,.u (.3.c.c.c. } } } }.Z.Z.a.a.a.a.aXC >.XX>XtXt T >XC.$.$.$.H p.=.; d.>., y .X=",
+" 'X;X;X;X;X;X;Xg.@.t.t.}.. t V cX>.B b X -.~Xf.u ( ~ :Xy Q g g.8.K aX8 p.H.G.G.1 u u.n.a.R.BX>.A T > >Xn.2XM.$ 0 p.=.;.:.> y. X=",
+".qX;.@.@.@.@.@Xg.#.t.t.e.R.^.B.A.^ b..X,Xe `Xf.u ( ~ :.Y Q g.8.8.K a p.H.H.G.1 u.D.<XM M F.N.^X2.E T./.]Xi u.$.$ 0.M.V.Z.>.,. .q",
+".qXBX:X:.#XBXBXBXBXB l.. vXtXtX2 AX6 XXe 2 ` ,.u ( ~ : Q Q g.8 dX8 p.H.H.G.1 u.D.<.<.<X#.a.).N )XtX$ T >Xi.D u.$X .M.=.;.Z.>. .q",
+".q WXBXBXBXBXBXBXVXV l.. v.AX2.! AX6 XX+.s ` , ( ~ :Xy Q g.I.8.K a p.H.G.2 u.D.<.<X#XlXlXiXC.N.BX>Xt T >XC.D.DXM.$ 0.M.V.Z.>XN.q",
+".q rXBXVXVXVXV '.&.tXu..XD c J.! b.e.TXj.sXf , ( ~ :Xy Q g.8.8 aX8.H.H.G u u.<.<X#XlXlXk.]Xi.R.BX>.A T > >XcXnXnXMX .M.=.;.:.c.q",
+".q.q 9.&.&.&.& ' 9.|Xu.. v c J.! b.e.T 2.sXf z ( ~ :.Y Q g.8.K a p.H.G.2 u.D.<X#XlXlXk.-Xl.9 F.N.^.!.E T./.]Xn.DXM.$ 0.=.;.>.q.q",
+".q.q r.& 9 9 9 ' 9.tXu.. v c J.! b.e.T 2.sXf z k ~ :.Y I g.8 d a p.H.G.2 u.<.<X#XlXk.-.-.-.-XiXC.X )XtX$./ >XiXcXM.$ 0.=.V.c.q.q",
+".q.q.q 9 9 9 9 ' +Xu./ v.B c.!.B b.e.T 2.sXf z k ~ :.Y I g.8 d a p.H.G u.D.<X#Xl PXk.-.-XAXA.9XC.X.BX>Xt T >XCXcXnXMX .M.V.q.q.q",
+".q.q.qXX.* q.m.m +.. vXt c c.!.B b.eX, 2.sXf z k ~ :.Y I.I.8 d a p.H.G u.D.<X#Xl PXk.-XAXAXAX0.].R VX>X2 T > >.]XnXMX .M.Z.q.q.q",
+".q.q.q r.m.m.m.m +.. v J J J.^ bX6 XX,Xj.s.~ z k ~ :.Y I g.8 d a p.H.GXM.D.<X#Xl P.-.-XAXA hXAX0 F.X.^.!.E T./.]XiXMX .M.j.q.q.q",
+".q.q.q.q '.m.m E $X-./ c J.! AX6.5.w.gXj x.~ z k ~ :.Y I g.8 d a p.H.GXM.D.<X#Xl PXk.-XAXA h h h.]XC.X )X>X$ T >XiXMX .V.q.q.q.q",
+".q.q.q.q.qXX B E $X-./ )X>.B bX6.5.'.gXe x.~ R k ~ :.YX1 g.> d a p.H.G.2 u.<X#XlXlXk.-XAXAXA h hXlXC.X.B.B.B T >.a M.M.q.q.q.q.q",
+".q.q.q.q.q r B B $X-./X$.B.B bX-.|XuXuXe x 3 3 3 3 : U 3 3 j j L p j j j j.S.< f f f f.-XA f f f j.].R.E.EX$.` >.a M }.q.q.q.q.q",
+".q.q.q.q.q.qXh B E.|X-././ bX6.|.tXuXuXeXq 3 3 3 3 YX4 3 3 j j L a j j j j.D.S f f f f.-.- f f f f.9 F./././.`XC.a.M.q.q.q.q.q.q",
+".q.q.q.q.q.q.q 'Xh ] $ r r $ +Xp !.'.gXe 2 %.~ z.4 YX4.Y I.I.8 d a p.H.GXM u.S.<X#XlXlXk.-.-.-.-XkXk.].aXCXC.aXi.n.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.{ 'XhXh r r E.i <.i.5.r -Xe.T.TX,.0.3 :.L % % @ d L O o.3.FXM.DXv .X< yXlXk.>.>.> }Xl.].c.c M MX .j.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.{ ' ' 'Xg <.}Xp ! ;Xr -XeXq.~ RX5 o YX4X1.,.I.P d a p.H.$XM u.D.S.SX#X#XlXlXlXlXlXlX#X#XcXn M.Q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.{ E ' ' <XsXp.r.[Xr.0XeXq % @ z o.3X4 U I.,.>.P L a p.H.$.$ u.DXc.SX#X#X#X#X#X#X#.SXcXn M.Q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.{ E 'Xg.iXp.r ! ;.0 -Xe %X7.6X5.3 YX4X1.,.I.> d.;.= p 0.$.$XMXn.DXc.S.S.S.SXcXcXnXn M.Q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.{ EXgXd.}Xp ! ;Xr -Xe.L % @ z o.3 Y UX1.,.I.P d.;.= p 0X .$XMXMXMXnXnXnXnXnXMXM.n.j.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q W <.}Xp.r !.w.0 = * %X7 R O o.3X4 . I.,.>.: d.;.=.M.M 0X .$.$XMXMXMXM M M.M.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q r <.}.r ! ;.w -Xe.L % @.6 o.3 YX4 . I.,.>.> d.;.V.=.M.M 0 0X X X X .M }.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q <Xp.r !.w.0 -XeXqX7 @ O o.3 YX4 . I.,.>.>.:.Z.;.V.=.=.=.M.M.M.V.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q $ l !.T.w.0 =.L %X7.6 O o.3 YXv . I y.,.>.>.Z.Z.;.;.V.V.Z.j.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q +.TX, -Xe.L % @.6 O o.3 YX4 .X1 y y.,.>.>.:.>.c.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.5.5X,Xe.L % @.6 O o.3X=X=Xv .. . . XN.c.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q",
+".q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q - *.L % @.6 O o o.3X=X=.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q"
+};
diff --git a/arts/builder/pics/Synth_FILEPLAY.xpm b/arts/builder/pics/Synth_FILEPLAY.xpm
new file mode 100644
index 00000000..76730eb0
--- /dev/null
+++ b/arts/builder/pics/Synth_FILEPLAY.xpm
@@ -0,0 +1,312 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 241 2",
+/* colors */
+" c #394684",
+" . c #FEFE82",
+" X c #FCF8EA",
+" o c #354280",
+" O c #664E4D",
+" + c #3C3352",
+" @ c #303C7B",
+" # c #2F3C7A",
+" $ c #2E3A79",
+" % c #282A5C",
+" & c #484C82",
+" * c #FFFFFA",
+" = c #2C3877",
+" - c #4D589E",
+" ; c #2A3675",
+" : c #FCFBF7",
+" > c #975F27",
+" , c #FFFEF0",
+" < c #384486",
+" 1 c #697095",
+" 2 c #222C6D",
+" 3 c #212C6C",
+" 4 c #303C7E",
+" 5 c #5A6390",
+" 6 c #FFE8B1",
+" 7 c #1C2667",
+" 8 c #EB9616",
+" 9 c #293477",
+" 0 c #FFFBE9",
+" q c #354086",
+" w c #475591",
+" e c #FEA50E",
+" r c #5363A0",
+" t c #1F2A6D",
+" y c #42518C",
+" u c #2F3A80",
+" i c #1E286C",
+" p c #F5DC68",
+" a c #50619D",
+" s c #2D387E",
+" d c #FFCD68",
+" f c #2B367C",
+" g c #1F2763",
+" h c #FFFEF6",
+" j c #283279",
+" k c #FEF2CA",
+" l c #FCBF3A",
+" z c #1A235E",
+" x c #384582",
+" c c #4C588F",
+" v c #232E74",
+" b c #DFE0E7",
+" n c #333F7D",
+" m c #F7E563",
+" M c #626DB5",
+" N c #3E4D8B",
+" B c #5C67AF",
+" V c #2A3574",
+" C c #FFF9C4",
+" Z c #273171",
+" A c #FFE799",
+" S c #354182",
+" D c #545FA7",
+" F c #FEDE8E",
+" G c #414E87",
+" H c #1D2767",
+" J c #3A458A",
+" K c #3A4680",
+" L c #323D82",
+" P c #E7CE8B",
+" I c #212B6E",
+" U c #1D276A",
+" Y c #FB9E0A",
+" T c #2C377C",
+" R c #353971",
+" E c #4C5C98",
+" W c #293379",
+" Q c #495895",
+" ! c #475693",
+" ~ c #232D73",
+" ^ c #222D72",
+" / c #FFA811",
+" ( c #455491",
+" ) c #212B71",
+" _ c #202B70",
+" ` c #43528F",
+" ' c #323E7B",
+" ] c #FEC548",
+" [ c #1D2663",
+" { c #2C3875",
+" } c #3A4886",
+" | c #FEFDB8",
+". c #374483",
+".. c #202A69",
+".X c #2F3A7B",
+".o c #1B2464",
+".O c #FDAD1F",
+".+ c #384287",
+".@ c #263072",
+".# c #FFFDE7",
+".$ c #253071",
+".% c #434E95",
+".& c #1E286A",
+".* c #9A8570",
+".= c #1C2668",
+".- c #4E5D99",
+".; c #485793",
+".: c #FCF487",
+".> c #202A6F",
+"., c #1F2A6E",
+".< c #C3822B",
+".1 c #1E286D",
+".2 c #1D286C",
+".3 c #2E3976",
+".4 c #3B4986",
+".5 c #FEF461",
+".6 c #FFCD55",
+".7 c #DC8715",
+".8 c #323F7D",
+".9 c #313D7C",
+".0 c #D89632",
+".q c #FEFD6E",
+".w c #FFFEFA",
+".e c #283373",
+".r c #273372",
+".t c None",
+".y c #39447D",
+".u c #FED678",
+".i c #242F6F",
+".p c #47548E",
+".a c #333F81",
+".s c #232D6E",
+".d c #414D92",
+".f c #FFD16F",
+".g c #1F296A",
+".h c #1E2769",
+".j c #2D397B",
+".k c #3E4A85",
+".l c #495893",
+".z c #563D40",
+".x c #242F72",
+".c c #61689A",
+".v c #232D71",
+".b c #FEB92F",
+".n c #212B6F",
+".m c #303B81",
+".M c #42508C",
+".N c #2E397F",
+".B c #1D276B",
+".V c #3E4C88",
+".C c #2A357B",
+".Z c #3D4A87",
+".A c #2C3673",
+".S c #263177",
+".D c #242F75",
+".F c #374481",
+".G c #787EA3",
+".H c #6872BB",
+".J c #B26E23",
+".K c #FFEFB7",
+".L c #232C6A",
+".P c #313C7B",
+".I c #FEFAD7",
+".U c #333973",
+".Y c #F69809",
+".T c #384685",
+".R c #564C67",
+".E c #5964AC",
+".W c #FFCC43",
+".Q c #404A90",
+".! c #FFFFFC",
+".~ c #FEB321",
+".^ c #3C468C",
+"./ c #D0B16E",
+".( c #283475",
+".) c #3B4781",
+"._ c #263273",
+".` c #2B336E",
+".' c #171F57",
+".] c #333E83",
+".[ c #45538E",
+".{ c #1E286B",
+".} c #1D286A",
+".| c #FFFFFF",
+"X c #1C2669",
+"X. c #4F5F9B",
+"XX c #4C5B98",
+"Xo c #3C4985",
+"XO c #C2791E",
+"X+ c #273277",
+"X@ c #483B52",
+"X# c #263076",
+"X$ c #253075",
+"X% c #465592",
+"X& c #7C5339",
+"X* c #222C72",
+"X= c #F3F3F3",
+"X- c #34417D",
+"X; c #343F7D",
+"X: c #202A70",
+"X> c #42518E",
+"X, c #404F8C",
+"X< c #3C4988",
+"X1 c #C8C7C2",
+"X2 c #364382",
+"X3 c #9E6D39",
+"X4 c #5761A9",
+"X5 c #252F6E",
+"X6 c #344180",
+"X7 c #3E4B8D",
+"X8 c #3C3C6A",
+"X9 c #2B3777",
+"X0 c #4A559C",
+"Xq c #FFD64F",
+"Xw c #475399",
+"Xe c #A8A9B6",
+"Xr c #FFDE66",
+"Xt c #FFFF73",
+"Xy c #1F296B",
+"Xu c #FDA20B",
+"Xi c #3E4990",
+"Xp c #1D2769",
+"Xa c #3F4C87",
+"Xs c #525F93",
+"Xd c #4B5A96",
+"Xf c #38438A",
+"Xg c #4A5A95",
+"Xh c #364188",
+"Xj c #FFE869",
+"Xk c #475692",
+"Xl c #44528F",
+"Xz c #34407C",
+"Xx c #292F64",
+"Xc c #FDB52F",
+"Xv c #43528E",
+"Xb c #1F296E",
+"Xn c #1E296D",
+"Xm c #999593",
+"XM c #404E8B",
+"XN c #2A357C",
+"XB c #7B6865",
+/* pixels */
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.@X+ 9 W j.S.D v ).>.{ H.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.A.PXf q.] u s f W.SX$.D ~X* ) _X:Xb.o z.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.tX<.%.d.^Xf q.] u s f W.SX$.D ~X* ) _.>.>XbXb.{ z.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t o - -Xw.%.Q.^Xf q L u sXN j.SX$ v ~X* ) _.>.>XbXn.1.1 iX z.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.tX4X4 D -Xw.%.Q.^Xf q L u s.C j.SX$ v ~X* ) _.>.,XbXn.1 i i.2.B.=.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.tXX M BX4 D -Xw.%Xi.^Xh q L.N T.C j.SX$ v ~X* ) _.>XbXbXn.1 i i.B.B.BX z.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.H M B.E D -X0Xw.dXi JXh.].m.N f.C j.SX$ v ~X* )X:.>XbXbXn.1 i i.B.B.B U U 7.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.M.H.H M BX4 D -X0.%.dXi JXh.].m.N f W jX#X$ ~ ^ ) ).>.>XbXb.1 i i.2.B.B U U U U.=.'.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t c.H.H M B.E D D -Xw.%.Q.^Xf q L u s f WX+X#.D ~ ^ ) ).>.,XbXn.1 i i.B.B.B U U UXpX 7.'.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.tXs.H.H.H M BX4 D -X0Xw.%Xi J.+.] L u T.C j.SX$ v ~X* ) _.>.,XbXn.1 i i.B.B.B U U UXpX X 7.'.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t c.H.H.H M B.E D D -Xw.%.Q.^ J. .].m.N f.C j.SX$ v ~X* ).>.>XbXbXn i i.B.B.B U U UXpXpX X .= 7.'.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.M.H.H.H M B.EX4 D -X0XwX7.).RXBXBXBXBXB &.yXz.U.3.A V Z.i.s I.>Xb.1 i i i.{.B.B U U UXpXpX .=.= 7.'.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.H.H.H M B BX4 D -X0Xw.%Xo.y O.<.<.<.*XmXm.G.G.c 5Xs.p.k.y.P V.@.s IXn i i i i.{.{.{.{.& UXpXp.=.= 7.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.H.H M M B.EX4 D - -Xw.%.d.yX@ O.J.<.<./X1X1X1X1XeXeXeXeXe.G.G.G.G 1 1.c.c & R.`XxXx %XxXx...hXp.&XpXp.o.t.t.t.t.t.t",
+".t.t.t.t.tXX M M B B.EX4 D - -X0.%.dXiX8 OX&X3.<.0./.I X :X=X=X=X=X=X= b b bX1X1X1XeXeXe.G 1.R.RX@X@X@Xx...gXy.g.&.& z.t.t.t.t.t",
+".t.t.t.t.t M B B.EX4 D D - -X0Xw.%Xi JX@X& >.7.0.0 P 0 ,.! : : : : :X=X=X=X= b b b b bX1X1Xm.*X3X&X&X&X@.L.. I 3XyXy.h.t.t.t.t.t",
+".t.t.t.tX4 B.EX4 D D D -X0Xw.%.%.Q.^ <X@.JXO.Y.O l F h.w.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| h , FXc.0XOXOXO.zXx.L.s.s 3 3 3.h.t.t.t.t",
+".t.t.t oX4X4 D D D - -X0Xw.%.%.Q.^.+X;.zXO.7.YXc d 6.w.!.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| ,.# P.0.<.J.J.J.zXx.L.i.i.s.s 2 3 [.t.t.t",
+".t.t.t - D D - - -X0XwXw.%.dXi.^ JX; RX& 8.Y Y ] F k.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| 0.I.f 8.<X3X3.JX@X5.i.@.$.i.i.s.s...t.t.t",
+".t.t.t - - -X0X0XwXw.%.%.dXi.^ JXh RX@X&.Y.YXu.6 6.I.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.I.K d 8.7.<.J > +.r.r.e.r.@.$.$.i.s.t.t.t",
+".t.tX<XwXwXwXw.%.%.%.dXi.^.^XfXh.]X8.z > Y YXu d k 0.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| k 6.6 e Y.Y.JX& +.( V.(.(.e.r Z Z.i g.t.t",
+".t.t.%.%.%.%.d.d.QXi.^.^ JXfXh.].m +X&.J Y e.O.u.# ,.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.! * k F ] e Y.Y >.zXxX9X9X9 ; V V.e.r ZX5.t.t",
+".t.A.d.Q.QXiXiXi.^.^ JXfXh q.].m.NX@ >XO Y.O.b F h.w.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| * h 6.f l / e YX&X@.` $ = = =X9 ; V.e.e Z...t",
+".t.P.^.^.^.^ J JXfXhXh q.] L.m.j.A.zXO.7 YXc.6 6 h.w.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.w h A.6.b / e 8X&X8.`.X $ $ $ = =X9 V V.e.L.t",
+".tXfXfXfXfXhXhXh q q.] L.m.m.N V.`.z.7.Y Y l.u.K.!.!.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.w , A ].b / 8.7 O R.U.9 @.X # $ = =X9 ; V.r.t",
+".t q q q q q.].] L L.m u.N s T.` +X&.Y.YXu.6 A k.!.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| ,.# F l.~.O 8.< O.U.P.8.8.9 @.X $ $ = = ; V.t",
+".@.].] L L L.m.m u u.N s T f.CXxX@ > Y Y e d k.#.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| 0.I.u.b.~.~.0.<.RXz n.a.a.8.8.9 @ # $ = = ;.e",
+"X+ u u u u.N.N.N s T f f.C j j +X&.J Y e.O.u.I 0.!.!.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.# C.u.b.~.~.<X3.R oX6 oX6X6X6.8.8.P # $ $ = V",
+" 9 s s s s T f f f.C.C W j.SX$ + >XOXu /Xc F.# , *.!.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.I 6.f.b.b.~.<XB.R. . X2X2 oX6X6 n.8.9 # $ $ {",
+" W f fXN.C.C.C W W j jX+.S.$.s.z.J.7Xu /.O.6 A 6.K k k.I.# 0 , h.w.w.!.!.|.|.|.!.! k AXr.b.bXcX3 OX8.T.T.T. . X2 oX6 n.8 ' # $ =",
+" j W W j j j j jX+.S.SX#X$.sXx.z.7.YXu e /.b ].6.u F A.K C.I.# 0 h h h.!.|.|.|.! *.K.:Xq.b.b.bX3.R.y } } }.T.T. X2 oX6 n.8.9 # $",
+".S.S.S.S.S.S.SX#X#X$X$X$.D.L %X& 8.YXu e /.~ l l ].6 d.f.u F F A A 6.K C k.I.#.#.# 6XjXq l l lXB.R.yX<X<.4 }.T x.F o o n.8.P $",
+".DX$X$X$X$X$X$X$.D v v ~ ~ % + > Y Y e e /.O.~.~.~.~.~.~.b.b.W.WXqXr.u.: A.K C C.I AXrXq.W l lXB &.) N.VX<X< } }.T x.F o oX-.8 #",
+" v.D.D v v v v ~ ~ ~ ~ ^ ) %.z > YXu e /.~ ].f.f d d d.6.6.6XqXqXqXrXrXrXj.:.:.: AXjXqXq.W l.0XB GXa N N N.VX<.4 }.T x.F o oX-.P",
+" ) ~ ~ ~ ~ ~ ~ ^ ^X*X* _.> + >XOXu e e.O.b.u k.K 6 6 6 A F.uXrXrXqXqXqXqXqXqXqXq mXqXqXqXq ]./XB GXMX,X, N N N.VX< } x.F oX- '",
+".>X*X*X*X*X*X* ) ) ) )Xy..X@.J.7 e e /Xc ].u.K A F A.K.K k.K 6 6 6 A A A.:XjXj mXqXqXqXqXq./.*.R.M.MX>X>X,X, N.V.VX< } x.F o n",
+".{ ) ) ) ) ) ) ) ) _.>.& g.z.7 8 e / / l d F 6 F d A k.#.! h , , , 0.#.I C A.:XjXqXqXqXqXq./.* 5Xl (Xl `X>.MX, N.V.V.4 } x oXz",
+" H _ _ _ _ _X:.>.>.>.> g %X& 8.Y e / / ] F F F.f ] F k.#.! * h h h h ,.#.I |.:Xj.5.5.5 m m./XB &X%X% ( ( ` `.MX, N.V.Z.4 x.FX-",
+".tX:.>.>.>.>.>.>.,.,Xb % +X& YXu e /.O.6 A F.f.6 l.u k.#.|.|.|.|.|.|.| * h C.:Xt.5.5.5.5 m.* 1 &.; ! !X% (XlX>.MXM N.V.Z } x.t",
+".tXb.>.>.,XbXbXbXbXbXb %.z > YXu /.O.~ d 6 F.6.6.W F.# ,.|.|.|.|.|.|.| * , | ..q.5.5.5 m p.* 5.p Q Q Q !X% (XlX>.MXM.V.ZXo .F.t",
+".t.oXbXbXbXbXbXbXnXn.2 %.z > Y e /.O.b.u k F.W ].6 A ,.w.|.|.|.|.|.|.| * , |Xt.q.5.5.q m p.* 5 cXdXd Q Q !X% (Xl yX, N.V.Z } '.t",
+".t zXbXnXnXnXn.1.1.1 i % +X& 8 8 /Xc ].u k F.W.6.u.K h.w.|.|.|.|.|.|.| ,.# |XtXt.q.q.q p./.*XsXg EXXXdXg.; !X% (Xv.MXM.V.ZXoXz.t",
+".t.t.{.1.1.1.1 i i i i [ %.z.7 8 /Xc.6 F k F ]Xr A C h.!.|.|.|.|.|.|.| ,.I | .Xt.q.q.q p./ 1X. E.-.- EXdXg.;Xk (Xl yX,.V.Z.).t.t",
+".t.t z.1 i i i i i i.B 7 g +.zX& >X3.*./X1 P P 6.K.I :.w.|.|.|.|.|.|.|.# C |XtXtXtXtXt P./ 1X..-X.X..- EXd Q.;X%XlX>X,.V.VXz.t.t",
+".t.t.t i i i i.2.B.B.BXpXp g % +X@.RXBXmXeX1X1 bX=X= : :.|.|.|.|.|.|.|.I |.:XtXtXtXtXt./Xm 1 a a a a.-.-XXXg.;Xk (Xv.MXM.V.t.t.t",
+".t.t.tX .2.B.B.B.B.B.BX .} H..XxXxXxX8X8 & 5 1 1.GXeXeX1X1 b bX= : :.w.I |.:XtXtXtXtXt./Xm 5 r r r aX..- EXg QXk (Xv.MXM.k.t.t.t",
+".t.t.t z.B.B.B.B.B.B U.B.{ t.n.v.$._.e.(X9.3 '.y & 5 1.GXeX1 b bX=X= : C A .XtXt . . .Xm 1Xs r r r a a.- EXd QXk (Xl.MXM K.t.t.t",
+".t.t.t.t.=.B.B U U U U U.{ t I.v.x._.(.( ; {.3.3.U.y & c 5 1 1.GXmXeXeX1 P P P.:.:.:.:Xm 1Xs r r r a a.- EXd QXk (Xv.MXa.t.t.t.t",
+".t.t.t.t.tX U U U U U U.{ t I.v.x._.( 9X9.j.X 4.8.a SX2.T.).k G c.c.GXmXm././ P P P PXm.cXs r r r aX..- EXg.lXk.[XvXM.t.t.t.t.t",
+".t.t.t.t.t z U U U UXp U.{ t I.s.x._.e 9X9 =.X @.8.a o S. x .).k.pXs 5 5 1.GXmXmXmXm 1Xs.- a a a aX. EXXXg.;X%.[Xv.).t.t.t.t.t",
+".t.t.t.t.t.t 7 UXpXpXpXp.&Xy I.s.x.@._ 9X9 = $ @.8.aX6X2. .T }X< N NX,X>Xl w cXs 5 5 1 5.-.- a aX.X..- EXd QXk w.[ G.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.=X X X Xp UXy I.s.i.$._.(X9 =.j.X.9.8X6 S. .T }X<.V NX,X>X>Xl.p.p.p c cXg E.-.-.-.- E EXdXg.; w.[ y.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.' 7X X X Xp.{ t 2.v.$._.( ;X9 $.X.9.8.a oX2.T }.4X< N NX,X> ` (X% !.;XgXdXX E E E EXXXdXg.;Xk ( y.y.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.' 7.=.=Xp.& t 3.s.$.@.e VX9 = $ @.8.aX6X2. .T }X<.V NX,.M `Xl (X% !.; QXgXgXdXdXgXg Q.;Xk ( y.y.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.' 7.=.=.&Xy I.s.i.@.e.(X9 = $.X.9.8X6 o. .T.T }X< N NX,.MX>Xl (X%Xk.;.; Q Q Q.l.;Xk w ( y.y.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.' 7.=Xp.g 3.s.i.$.r.( ; = $ # @.8X6X6X2. }.4.V.V NX,.MX>Xl ( (X%XkXkXkXkXkX% w.[ y.y.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.' 7Xp.&Xy 3.s.i.@.e VX9 = $.X.9.8X6 oX2 x.T }X<.V.V NXM.M yXvXlXl ( ( ( (.[.[.[ y.y.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.o.&Xy 3.s.i.$.r V ; = = $ @.8 nX6 o.F x.T }X<.V.V NXMX,.M yX>XvXvXlXvXvXv G.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t z.h 3 2.s.$ Z.e VX9 = $ #.P.8 nX6 o.F x }.4.Z.V.V NXMX,X,.M.M.M.MXM.).t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.h 3.s.i Z.r.e VX9 = $ #.9.8 n o o.F x }.4.Z.Z.V.V.V.VXMXMXMXa.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t [...s.i Z.e V ; = = $ # '.8 n o o.F x }Xo.Z.Z.Z.V.V.k K.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t gX5 Z.e V ; = $ $ #.9.8X- o o.F x x }Xo.)Xz.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t...L.r V ; = $ $ #.P.8X-X- o o.F x.F 'Xz.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t",
+".t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.e V { = $ $ #.P ' nXzX-.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t"
+};
diff --git a/arts/builder/pics/Synth_MIDI_DEBUG.xpm b/arts/builder/pics/Synth_MIDI_DEBUG.xpm
new file mode 100644
index 00000000..14dcd697
--- /dev/null
+++ b/arts/builder/pics/Synth_MIDI_DEBUG.xpm
@@ -0,0 +1,323 @@
+/* XPM */
+static char * MIDI_DEBUG_xpm[] = {
+"64 64 256 2",
+" c None",
+". c #161E54",
+"+ c #5A6A9C",
+"@ c #364684",
+"# c #4A5A8C",
+"$ c #8692B4",
+"% c #727EA4",
+"& c #26326C",
+"* c #46527C",
+"= c #5A5E8C",
+"- c #6A769C",
+"; c #323E6C",
+"> c #42467C",
+", c #526294",
+"' c #666A94",
+") c #7E8AAC",
+"! c #9AA6C4",
+"~ c #525A84",
+"{ c #4A527C",
+"] c #2E3A6C",
+"^ c #3A3E74",
+"/ c #7E829C",
+"( c #5A6694",
+"_ c #1E2A64",
+": c #929EBC",
+"< c #6A76BC",
+"[ c #3E4E84",
+"} c #62729C",
+"| c #424E7C",
+"1 c #66729C",
+"2 c #4A5294",
+"3 c #3A468C",
+"4 c #7276A4",
+"5 c #323E84",
+"6 c #525AA4",
+"7 c #5E6AAC",
+"8 c #929ABC",
+"9 c #7A86AC",
+"0 c #2E366C",
+"a c #868AA4",
+"b c #262E64",
+"c c #3E4674",
+"d c #7A7E9C",
+"e c #363E6C",
+"f c #525E8C",
+"g c #4A5684",
+"h c #5A66AC",
+"i c #626A8C",
+"j c #4E5A9C",
+"k c #8E9ABC",
+"l c #2A366C",
+"m c #5A62A4",
+"n c #6676A4",
+"o c #5662A4",
+"p c #2A3A7C",
+"q c #424E8C",
+"r c #6A72AC",
+"s c #8E92B4",
+"t c #465294",
+"u c #AAB2CC",
+"v c #62668C",
+"w c #222E64",
+"x c #1A2664",
+"y c #5A6284",
+"z c #424A8C",
+"A c #566694",
+"B c #666EB4",
+"C c #A2A6C4",
+"D c #7E82AC",
+"E c #6E729C",
+"F c #868AB4",
+"G c #4E5E94",
+"H c #8A96B4",
+"I c #7682A4",
+"J c #26327C",
+"K c #666E94",
+"L c #3A4284",
+"M c #9AA2C4",
+"N c #4A5694",
+"O c #727A9C",
+"P c #6E76A4",
+"Q c #3A4A7C",
+"R c #4A5A94",
+"S c #46568C",
+"T c #32427C",
+"U c #424A74",
+"V c #52629C",
+"W c #828EB4",
+"X c #525A94",
+"Y c #4A528C",
+"Z c #5A669C",
+"` c #222A74",
+" . c #4A4E7C",
+".. c #6672A4",
+"+. c #3A4A8C",
+"@. c #324284",
+"#. c #525E9C",
+"$. c #626EB4",
+"%. c #3E4A7C",
+"&. c #364274",
+"*. c #525E94",
+"=. c #4A568C",
+"-. c #626E94",
+";. c #323A7C",
+">. c #5A6294",
+",. c #868EB4",
+"'. c #727AAC",
+"). c #162254",
+"!. c #5E6E9C",
+"~. c #8A92B4",
+"{. c #767EA4",
+"]. c #2A326C",
+"^. c #42528C",
+"/. c #2E3E7C",
+"(. c #828AAC",
+"_. c #9EAACC",
+":. c #565A84",
+"<. c #323A6C",
+"[. c #3A4274",
+"}. c #222A64",
+"|. c #96A2C4",
+"1. c #464E7C",
+"2. c #5E6AB4",
+"3. c #7A82A4",
+"4. c #464E8C",
+"5. c #7E86AD",
+"6. c #666EA4",
+"7. c #4E5699",
+"8. c #424A84",
+"9. c #6E7AC0",
+"0. c #8A8EAC",
+"a. c #A2AACC",
+"b. c #7E86A4",
+"c. c #4E5E9C",
+"d. c #8E96BC",
+"e. c #465694",
+"f. c #6E7AA5",
+"g. c #6672BC",
+"h. c #1A2264",
+"i. c #2E367C",
+"j. c #262E74",
+"k. c #3E4684",
+"l. c #363E7C",
+"m. c #626A9C",
+"n. c #2A367C",
+"o. c #62669C",
+"p. c #222E74",
+"q. c #5E6A9A",
+"r. c #3A4682",
+"s. c #4E5A8B",
+"t. c #6E769C",
+"u. c #566293",
+"v. c #9EA6C6",
+"w. c #4E5284",
+"x. c #5E6693",
+"y. c #969EC4",
+"z. c #6A729B",
+"A. c #626AA4",
+"B. c #969ABC",
+"C. c #565E8A",
+"D. c #4E5684",
+"E. c #6A76A5",
+"F. c #2E3A7D",
+"G. c #1E266B",
+"H. c #5E628C",
+"I. c #6A6E94",
+"J. c #9EA2BC",
+"K. c #767AA4",
+"L. c #464A7C",
+"M. c #3E4A8E",
+"N. c #364285",
+"O. c #565EA1",
+"P. c #8A8EB5",
+"Q. c #1A225C",
+"R. c #3E4274",
+"S. c #8286AC",
+"T. c #A6AAC4",
+"U. c #3E468C",
+"V. c #363E84",
+"W. c #5E66AC",
+"X. c #2A327C",
+"Y. c #4E5A94",
+"Z. c #56629C",
+"`. c #4E528C",
+" + c #5E669C",
+".+ c #6A72A4",
+"++ c #565E94",
+"@+ c #4E568C",
+"#+ c #5E6294",
+"$+ c #767AAC",
+"%+ c #46528C",
+"&+ c #323E7C",
+"*+ c #626AB4",
+"=+ c #8692BC",
+"-+ c #727EAC",
+";+ c #263274",
+">+ c #465284",
+",+ c #5A5E94",
+"'+ c #323E74",
+")+ c #666A9C",
+"!+ c #7E8AB4",
+"~+ c #525A8C",
+"{+ c #4A5284",
+"]+ c #2E3A74",
+"^+ c #7E82A4",
+"/+ c #1E2A6C",
+"(+ c #929EC4",
+"_+ c #3E4E8C",
+":+ c #6272A4",
+"<+ c #424E84",
+"[+ c #4A529C",
+"}+ c #929AC4",
+"|+ c #7A86B4",
+"1+ c #2E3674",
+"2+ c #262E6C",
+"3+ c #3E467C",
+"4+ c #7A7EA4",
+"5+ c #363E74",
+"6+ c #626A94",
+"7+ c #4E5AA4",
+"8+ c #2A3674",
+"9+ c #5A62AC",
+"0+ c #5662AC",
+"a+ c #424E94",
+"b+ c #46529C",
+"c+ c #626694",
+"d+ c #222E6C",
+"e+ c #5A628C",
+"f+ c #424A94",
+"g+ c #56669C",
+"h+ c #6E72A4",
+"i+ c #8A96BC",
+"j+ c #7682AC",
+"k+ c #666E9C",
+"l+ c #3A428C",
+"m+ c #4A569C",
+"n+ c #727AA4",
+"o+ c #3A4A84",
+"p+ c #424A7C",
+"q+ c #525EA4",
+"r+ c #3E4A84",
+"s+ c #36427C",
+"t+ c #626E9C",
+"u+ c #323A84",
+"v+ c #868EBC",
+"w+ c #8A92BC",
+"x+ c #767EAC",
+"y+ c #2A3274",
+"z+ c #828AB4",
+"A+ c #565A8C",
+"B+ c #323A74",
+"C+ c #3A427C",
+"D+ c #222A6C",
+"E+ c #464E84",
+"F+ c #7A82AC",
+"G+ c #464E94",
+" ;+y+y+X.X.;+j.p.` D+/+G. ",
+" }.B+N.N.u+F.F.n.J j.;+j.p.p.D+d+Q.. . . ",
+" 0 8.M.U.l+N.5 F.i.i.n.J ;+j.` p./+/+/+G.h.h.. . ",
+" B+j 7.m+G+f+3 N.V.u+F.F.n.J j.p.p.p.` p.p.` /+/+x h.. . . . ",
+" X O.O.7.b+a+M.3 N.@.u+i.n.n.n.X.;+j.p.` /+/+/+/+` /+/+G.G.h.. . ",
+" @+*+h 9+7+m+[+a+f+3 l+V.5 F.i.X.J ;+j.p.p.p.` ` ` G./+/+G./+G./+h.. . . ",
+" 6.$.2.0+O.6 m+G+f+U.3 l+5 u+F.i.X.J J j.j.` p./+/+` G./+` G./+G./+G.x h.. . ",
+" E+< g.*+W.9+q+7+m+b+f+M.l+V.u+/.F.n.n.y+;+;+p.d+` p.` /+/+G.G./+G./+G.G.G.G.h.. . . ",
+" R.E.g.g.2.h 0+7+m+b+a+M.3 3 @.u+u+p n.J J j.p.j.p.` p.` /+/+` G./+G.G.x G.G.G.G.h.. . . ",
+" @+9.g.g.2.h 0+6 7.[+a+a+f+3 l+V.5 i.i.X.y+j.;+j.p.D+` /+/+/+/+/+/+G./+/+/+x /+/+G./+h.. . . ",
+" R.r < B $.2.0+q+j m+2 a+M.3 N.@.F.F.i.n.n.;+j.j.p.p.d+` p./+/+` G./+G.x G./+G.G./+x G.x h.. . . ",
+" <+9.< g.B W.9+O.#.O. +Z.X M.3 N.V.5 B+F.1+;+J ;+;+j.p./+/+/+` G.G./+G./+/+G.x G.x G.G./+G.G.h.. . . ",
+" B g.B *+2.h m m +.+4+o.7.z l+V.^ r+{+p+C+1+j.p.p.D+` D+D+/+/+/+` /+G.G./+x /+/+G./+G.G.G.x x h.. . ",
+" r g.g.$.2.9+o h r v+B.a.f.@+r+V.r+++I.S.P H.5+& j.d+d+d+2+].D+/+/+` /+/+/+/+` G.G./+/+/+/+/+G.G./+h.. . ",
+" p+B *+2.h 0+o 6 6 A.W w+}+6.Y Y .~+x.q.6+m.6+3+y+y+1+5+p+[.5+2+/+/+/+p.` p.y+;+;+p./+/+/+/+/+/+G.G.G.x . . ",
+" *+2.W.h 9+o 6 j R #+F F F +z ++n+.+)+= @+>.I.E+]+C+<+' ,.i 1.l ` p.p.p.8+5+>+p+s+y+p.p.p.d+d+d+w d+_ G.).. ",
+" 7.h h 0+V q+7+7.[+2 m P.x+h+#+7.o.F+x.1.L.| `.C.> ]+R.=.4 B.v e l 2+y+]+s+E+C.1 A+%.1+2+2+2+& 0 [.U [.] 2+_ x . ",
+" l.0+0+q+6 6 7.j m+G+q >.d.4 ++++++- ,.D.1+&+R.%.E+C+i.r.A+4+T.= ] ].;+]+3+#+4+a B.z.{+B+;+& ].[.:.K F+' D.<.D+}.. . ",
+" 4.6 6 6 7+7+[+b+t z 4. +v+t+=.++)+I.P E+1+5+ .> &.1+].'+g K (. .].;+;+F.C+u.z+F ~.c+%.5+1+[.w.~ H.' 4 z.' c & 2+D+Q. ",
+" 7+7.m+m+[+b+b+b+a+z >.z.z+>.z *.'.1 #+^ y+l.e+%.1+].j.0 L.:.I.[.& y+y+8+T C.0.,.P.u.C+s+r.u.b.n+1 K 6+E {.w.0 & w x ",
+" 0 m+m+b+b+G+a+f+M.M.8.)+I..+Y C+~+4+z.( | B+3+C.[.8+;+;+<.C.~ D.<.& 8+8+1+l.s.0.5.{.~ C+p+D.k+S.v 1.1.* e+f.{ 0 & 2+d+x ",
+" G+a+a+G+f+f+M.M.3 N.Y x+A.A+k.u+Y (.h+#+@+<+D.= 5+;+y+].e E ~ R.0 8+8+n.8+]+D.,.{.I.g r.s.P {.b.D.5+'+5+{ E 1.] ].& }.. ",
+" x z f+M.M.M.M.3 l+l+N.k.~+%+k.l.F.8.n+n+h+' >.D.p+1+;+;+].c t.{ ; 8+n.i.F.]+C+C.P.P >.Y p+e+F+n+z.| ] '+3+{ x.c l & ;+l & x ",
+" ;.U.3 3 3 3 l+l+l+V.;.&+k.&+;.F.1+3+)+4 (.F+$+@+s+1+8+].] .d 1.0 1+p F.p B+1.6+P.k+Y g %+m.P.t.e+[.]+5+| D.~ [.0 8+8+y+b . ",
+" &+l+l+l+N.N.N.N.@.5 5 F.;.F.i.n.n.]+%. .~+D.{+^ p y+n.l [.1.y [.8+1+F.F./.r.e+- (.( 8.E+{+1 d.z.s.C+]+[.~ D.E+5+1+1+8+8+y+& ",
+" N.5 5 5 5 V.5 5 u+u+i.i.i.n.n.y+y+y+y+]+'+&+;.8+y+8+n.1+U 1. .'+]+F./.&+;.%.n+4+5.C.r.<+=.E J.K 1.[.'+p+K ~ %.'+]+p ]+1+l ]. ",
+"j.5 5 5 u+u+u+F.F.F.F.F.n.X.n.n.J ;+;+j.y+y+8+1+8+n.n.F.]+5+'+5+]+F.&+5 /.;.E+f.E..+g @ %.%+z.M {.u.Y <+f t.~ [.B+B+F.]+F.p p l ",
+"y+u+u+u+F.p p i.n.8+1+n.y+8+;+;+y+;+J ;+;+;+;+n.n.n.8+n.i.]+]+F.;.&+5 5 &+s+>+z.m.u.8.s+r.>+K M z+t.1 ( z.4+D.&./.F././.]+]+1+8+",
+";+n.n.i.i.i.i.u+^ r+R.N.y+j.j.p.j.j.;+;+y+y+;+X.n.p F.p i.F.]+/.&+5 s+N.s+s+r+=.>+q r.r.r.[ #+(.(.F+x+n+E.1 >+&.'+&+;.&+;.F.F.1+",
+"n.i.X.n.n.n.5 8.u.K.x.Y ;.;+;+j.p.y+y+8+;+J X.8+F.i.n.F./.;./.5 5 N.@.N.@.N.s+r.r.@ r.@ r.8.f n+9 d.P.z+- >.<+s+s+l.T &+&+'+]+p ",
+"J X.J X.8+F.k.,+.+z+x.%.1+j.;+].B+p+R.C+0 8+n.8+8+]+]+;./.&+&+T @.N.N.L N.@ N.@ r.@ 3 r.3 o+<+@+C.q.q.x.s.E+r.N.s+N.s+T &+&+;.]+",
+";+J j.;+X.B+=.'.a B.x.C+y+` l 8.C.n+q.D.B+;+8+n.]+l.[.r.s+&+&+5 N.N.@ @ @ 3 o+3 +.M.M.M.o+M.o+[ <+| E+%+r+r.r.@ @ N.N.l.@.&+&+F.",
+"j.;+p.j.j.y+1.4 x+D {+0 ].j.B+C.h+a x.<+B+;+1+&+%.s.C.e+{+r+s+5 N.N.@ r.r.r.o+r++.M._+_++.M.r+r+r+[ r+[ o+r.r.r.r.@ @ s+s+T T &+",
+"p.j.j.j.p.2+C+t.t.t.R.d+p.2+> P F J.x.[.]+8+&.~+I.S.F P..+f r+s+N.r.l+r.r.r+M.+.M._+_+q q q q _+_+M.[ M.r+M.r++.o+r.@ N.N.V.l.F.",
+"` p.p.p.p.2+%.{.m.~+B+D+d+d+3+P F+0.D.1+<.B+{+z.P f.F+,.h+++%+r.o+r+^.@+@+@+>+[ _+_+_+_+_+_+M.q _+z q _+_+_+M.M.o+k.o+@ @ s+s+&+",
+"/+` d+` D+2+ .D = 3+& D+/+p.[.z.O {.p+l B+p+x.$ n+m.n+z+- x.=.<+t s.m.j+-+f.G 4.q q a+^.^.>+>+<+^.^.^.^.q q _+[ M.o+r.r.r.N.s+&+",
+"/+` d+/+2+5+A+{.{+1+d+/+D+2+8.K.k+e+^ l [.H.c+k+C.{+x.x+z.m., @+Z.t+j+d.!+x+, ^.q ^.4.%+s.( ( >.g q q ^._+q _+_+M.r+o+r.r.@ @ s+",
+"G./+/+` ].D.x.P 3+2+/+G.D+y+{+5.x.1.B+& %.3.v {+%.s+=.f...t+ +V P z+d.v.~.j+++%+^.^.# x.f.,.$ ~.t+# %+^.^.^.q q _+_+M.o+o+r.C+&+",
+" ` /+/+B+H.e+++B+}.D+G.d+[.C.D ~ '+B+0 { 3.C.R.r.r.@+f.6.Z *.=.t+(.d.v.z+E.*.=.Y.u.-.x+5.w+i+d.n+( # t t e.^.^._+[ M.o+r.@ r. ",
+" /+/+D+[.P C.p+2+/+G./+].Y 6+b.E+0 0 e ~ b.{ '+C+%.*.P q.*.Y q >.) d.v.F+q.u.Y.m.F+~.|.8 ~.d.y.) f.*.S S t %+4.q q [ M.r+r.@ ",
+" . G.}.0 `.C+0 D+/+x /+B+#+x.6+[.& <.1.v 5.D.T k.{+m t.u.%+<+[ ,+(.~.: f.Z.( Z f.w+,.!+-+- j+d.5.n+u.S S e.e.%+^.q _+_+r+r.'+ ",
+" Q./+/+& '+].D+G.x /+D+C+I.#+D.B+& [.i f.5.s.C+>+x.k+.+~+r+o+k.f ,.$ w+1 *.+ f.,._.W f.q.*.1 z+j+f.u.R e.e.S e.^.^.q r++.c b ",
+" Q.G.D+d+/+/+G.G./+w '+++E+[.y+2+5+H.z.3.u.p+f 1 t+u.%+r.r+[ x.s F 5.t+*.t+j+w+J.I q.g+*.} ~.x+..*.R N e.e.t ^.q q [ o+r. ",
+" h.G.x G.G.G./+/+G.D+1+1.5+& & ;+5+= K 4+6+~+)+4+x.=.k.r.r+Y 1 y.!+'.t+V ..=+d.|.P u.*.*.} i+-+q., R R N e.S t ^.^.q [ & ",
+" h.x /+x G.G./+G.}.d+].].2+d+2+] E+e+K.- 1 -. +Y Q r.@ <+C.f.8 j+t+ +Z.P d.i+i+k+*.V Z.P k % Z *.R R R e.e.e.^.q q [ ",
+" G./+x /+/+/+G.G.x G.D+/+D+d+;+8+[.@+t.3.(.)+D.3+N.N.r.<+- F+w+P Z.A g+j+|.s ) !.G u.q.% i+E.( G G c.R R e.^.^.^._+[. ",
+" . h.G.G.x x x G.G.x D+d+p.d+p.& l s+E+D.f <+r.s+s+N.r.=.{.9 W 1 *.*.*.-+_.d.!+:+V q.E.j+W n g+c.R j R R N t ^.q q r. ",
+" G.G.G.G.G.G.G.G./+/+/+d+;+;+y+8+0 B+l.&.&.T s+@ r.r.@+F+F+F+( N s.G n+u B.z+1 Z.n W !+5.t+V *.c.G R N e.S ^.^.Q ",
+" h.G./+/+x /+G.G.D+` D+2+;+;+8+8+8+]+;.;.&+&+N.@ r.>+m.q.q.s.^.N *.E.v.8 w+9 E.j+=+!+-+q.V c.c.j R R e.%+%+[ ",
+" )./+G.G./+x G./+/+d+p.;+j.;+8+8+]+F.F.&+T N.N.s+r.[ =.Y.7.^.4.S s.z.(+(+8 i+w+i+i+j+n + V G R R R e.t S ^.0 ",
+" . G.G.G./+G./+/+D+D+& ;+;+8+n.8+]+F.F.T T N.@ L o+r+^.q ^.q ^.R q.5.=+}+d.w+w+W f.7 , c.G c.R N S t ^.<+ ",
+" x x x x x G.G.d+p.p.j.;+;+8+i.p /.5 &+N.s+N.@ r.o+r+[ M.^.%+e.++E.9 8 i+i+W !+n g+*.G R R R R e.S ^. ",
+" . h.G.G.x /+G./+D+d+j.y+;+8+1+i.F.&+&+@.T N.N.r.3 U.[ M._+q ^.N , q.f.f.f.E...g+G Y.j R N e.=.^.4.c ",
+" . x x G.G./+/+d+p.j.;+8+8+8+p F.F./.l.s+@ r.r.o+o++._+q _+^.%+N Y.*.Z.+ g+#.Y.Y.R R e.R S e.>+l ",
+" . . x x /+/+d+d+d+j.;+8+1+]+]+;./.5 &+T N.N.r.U.r+_+q q ^.^.^.e.N Y.Y.R Y.R R e.R e.e.^.^.c ",
+" Q.G.G.G.G.D+d+p.;+;+;+8+8+F.F.;.&+s+N.@ r.r.o++.r+_+_+_+q t %+S %+S =.e.e.e.e.%+%+%+>+l ",
+" . . _ /+/+d+d+2+;+;+8+8+p F.F.F.&+&+@.@ N.r.+.r.M.r+_+_+q _+^.a+^.S %+%+S e.e.%+^.r. ",
+" h.G.D+D+d+;+;+;+y+8+1+]+/.&+&+V.s+s+@ N.@ o+o+_+M.<+_+q q ^.^.^.^.^.^.^.^.^. ",
+" . _ /+D+d+2+;+y+8+8+1+]+F./.&+5 s+s+L r.r.r.r++.[ _+_+q q q ^.^.a+q [ r. ",
+" G.d+D+;+& ;+;+8+8+F.]+&+&+&+5 s+@ N.r.r.o+k.r+r+[ _+_+_+_+q <+[ ",
+" x _ p.& ;+;+8+8+p 1+F./.'+&+&+s+N.@ N.@ r.o+3 r+r+r+M.r+r+r. ",
+" _ 2+y+;+y+1+p ]+B+/.&+&+T T s+@ r.@ r.o+r.o+r.&. ",
+" w w & 8+8+p F././.;.&+l.l.s+N.N.C+@ &+s+ ",
+" y+8+1+1+]+/.&+/.&+&+s+s+ "};
diff --git a/arts/builder/pics/Synth_MIDI_ROUTER.xpm b/arts/builder/pics/Synth_MIDI_ROUTER.xpm
new file mode 100644
index 00000000..43b8a59d
--- /dev/null
+++ b/arts/builder/pics/Synth_MIDI_ROUTER.xpm
@@ -0,0 +1,323 @@
+/* XPM */
+static char * Synth_MIDI_ROUTER_xpm[] = {
+"64 64 256 2",
+" c None",
+". c #161E54",
+"+ c #AE922C",
+"@ c #4A5A94",
+"# c #363E64",
+"$ c #DECA34",
+"% c #3E4E84",
+"& c #D2AE1C",
+"* c #222E64",
+"= c #A6721C",
+"- c #42425C",
+"; c #3A3A54",
+"> c #FEE61C",
+", c #626EB4",
+"' c #FEAE04",
+") c #3A4674",
+"! c #2E3664",
+"~ c #CE9214",
+"{ c #52669C",
+"] c #4A4E84",
+"^ c #E2DA4C",
+"/ c #2E3E7C",
+"( c #CABE5C",
+"_ c #2A2E5C",
+": c #CEA21C",
+"< c #565E94",
+"[ c #A68224",
+"} c #FACA14",
+"| c #3E427C",
+"1 c #CE8A14",
+"2 c #1A2664",
+"3 c #46568C",
+"4 c #D6AE24",
+"5 c #3E4E8C",
+"6 c #B28A24",
+"7 c #3E4A7C",
+"8 c #52629C",
+"9 c #FABE0C",
+"0 c #D29A14",
+"a c #4A5A9C",
+"b c #363E84",
+"c c #22265C",
+"d c #FEF62C",
+"e c #4A5694",
+"f c #2A3274",
+"g c #D6B624",
+"h c #464E8C",
+"i c #3A3E6C",
+"j c #222E74",
+"k c #323A74",
+"l c #2A367C",
+"m c #FAD214",
+"n c #DED23C",
+"o c #364684",
+"p c #2A3264",
+"q c #3E4A8C",
+"r c #D69E14",
+"s c #BE9A2C",
+"t c #323664",
+"u c #5E66AC",
+"v c #DEA614",
+"w c #B28224",
+"x c #525AA4",
+"y c #6A76BC",
+"z c #FAB60C",
+"A c #565EA4",
+"B c #B68A24",
+"C c #FAC60C",
+"D c #CE9E14",
+"E c #36427C",
+"F c #222A6C",
+"G c #DEBA24",
+"H c #323A64",
+"I c #BA9224",
+"J c #364274",
+"K c #26326C",
+"L c #FEEE24",
+"M c #2E3A74",
+"N c #4A528C",
+"O c #FEDA14",
+"P c #32427C",
+"Q c #DABE2C",
+"R c #D2AA1C",
+"S c #FACE14",
+"T c #3E467C",
+"U c #1E2A6C",
+"V c #42528C",
+"W c #464A84",
+"X c #FEFE34",
+"Y c #4A569C",
+"Z c #D6BA2C",
+"` c #46528C",
+" . c #E2D644",
+".. c #3A4A84",
+"+. c #2A326C",
+"@. c #36428C",
+"#. c #162254",
+"$. c #525A8C",
+"%. c #323E74",
+"&. c #C6B654",
+"*. c #262E64",
+"=. c #464A64",
+"-. c #2A3674",
+";. c #D69614",
+">. c #5A66AC",
+",. c #CEA61C",
+"'. c #1E266C",
+"). c #DEB21C",
+"!. c #424A7C",
+"~. c #FAC20C",
+"{. c #4E5E9C",
+"]. c #222A5C",
+"^. c #3A426C",
+"/. c #263274",
+"(. c #2E3A7C",
+"_. c #FAD61C",
+":. c #BA8224",
+"<. c #FABA0C",
+"[. c #5662A4",
+"}. c #D29E14",
+"|. c #363A64",
+"1. c #FEE21C",
+"2. c #DAC634",
+"3. c #3E468C",
+"4. c #DECE3C",
+"5. c #464E74",
+"6. c #D2B224",
+"7. c #3E466C",
+"8. c #FEEA24",
+"9. c #AA7E24",
+"0. c #AE8624",
+"a. c #4E5274",
+"b. c #6672BC",
+"c. c #5A629C",
+"d. c #D6B224",
+"e. c #AE8E2C",
+"f. c #5E6AB4",
+"g. c #6E7ABC",
+"h. c #B6962C",
+"i. c #4E5E94",
+"j. c #D29614",
+"k. c #AA8624",
+"l. c #CE8E14",
+"m. c #B28624",
+"n. c #B68E24",
+"o. c #C69A24",
+"p. c #3A4A7C",
+"q. c #525E9C",
+"r. c #FEF22C",
+"s. c #FEDE14",
+"t. c #DAC234",
+"u. c #E6A614",
+"v. c #FEB204",
+"w. c #FEFA2C",
+"x. c #1A2264",
+"y. c #2A2E6C",
+"z. c #323A84",
+"A. c #4A529C",
+"B. c #FEFE44",
+"C. c #46529C",
+"D. c #464E84",
+"E. c #5666A4",
+"F. c #323E7C",
+"G. c #FECA0C",
+"H. c #1E265C",
+"I. c #DAAE1C",
+"J. c #424E8C",
+"K. c #4E5AA1",
+"L. c #4E5692",
+"M. c #DAB624",
+"N. c #E2D244",
+"O. c #3A4686",
+"P. c #2E3262",
+"Q. c #424A94",
+"R. c #FEB604",
+"S. c #3A427C",
+"T. c #FECE0F",
+"U. c #42467C",
+"V. c #1A225C",
+"W. c #262A64",
+"X. c #FED614",
+"Y. c #FEBA04",
+"Z. c #5A62AC",
+"`. c #B28E24",
+" + c #B2922C",
+".+ c #666EB4",
+"++ c #D29214",
+"@+ c #D2A21C",
+"#+ c #FEBE0C",
+"$+ c #262E74",
+"%+ c #2E367C",
+"&+ c #FED214",
+"*+ c #DA9E14",
+"=+ c #FEC60C",
+"-+ c #4E569C",
+";+ c #DABA2C",
+">+ c #2E326C",
+",+ c #3A428C",
+"'+ c #363E74",
+")+ c #2E3674",
+"!+ c #D2A61C",
+"~+ c #FEC20C",
+"{+ c #DEC634",
+"]+ c #626AB4",
+"^+ c #BA962C",
+"/+ c #D28E14",
+"(+ c #B68624",
+"_+ c #BA8E24",
+":+ c #363E6C",
+"<+ c #DECA3C",
+"[+ c #D2AE24",
+"}+ c #222E6C",
+"|+ c #FEE624",
+"1+ c #3A467C",
+"2+ c #2E366C",
+"3+ c #5266A4",
+"4+ c #2A2E64",
+"5+ c #465694",
+"6+ c #3E4A84",
+"7+ c #D29A1C",
+"8+ c #2A327C",
+"9+ c #D6B62C",
+"0+ c #464E94",
+"a+ c #3A3E74",
+"b+ c #DED244",
+"c+ c #3E4A94",
+"d+ c #32366C",
+"e+ c #CE9E1C",
+"f+ c #364284",
+"g+ c #222A74",
+"h+ c #323A6C",
+"i+ c #4A5294",
+"j+ c #324284",
+"k+ c #3E4684",
+"l+ c #425294",
+"m+ c #FEFE3C",
+"n+ c #465294",
+"o+ c #E2D64C",
+"p+ c #3A4A8C",
+"q+ c #525A94",
+"r+ c #262E6C",
+"s+ c #424A84",
+"t+ c #222A64",
+"u+ c #3A4274",
+"v+ c #26327C",
+"w+ c #2E3A84",
+"x+ c #5662AC",
+"y+ c #D29E1C",
+"z+ c #363A6C",
+"A+ c #3E4674",
+"B+ c #6E7AC4",
+"C+ c #525EA4",
+"D+ c #FEDE1C",
+"E+ c #323E84",
+"F+ c #1E2664",
+"G+ c #424E94",
+" /.f f 8+8+/.$+j g+F U F+ ",
+" ].k f+f+z.w+(.l v+$+/.$+j j F j x.. . . ",
+" d+s+q 3.,+f+E+w+%+%+l v+/.$+g+j U U U '.x.x.. . ",
+" k K.-+Y G+c+3.@.b z.w+(.l v+$+j j j g+j j g+U U 2 x.. . . . ",
+" q+A C+Y A.0+c+O.@.j+z.%+l l l 8+/.$+j g+U U U U g+U U '.'.x.. . ",
+" L.]+>.x+x -+C.G+c+O.@.b E+w+%+8+/./.$+j }+j g+g+g+'.U U '.U '.U x.. . . ",
+" , , f.Z.C+K.Y 0+Q.3.3.@.E+z.w+%+8+v+v+$+$+g+}+U U g+'.U U '.U '.U '.2 x.. . ",
+" % y b.]+u x+A K.Y C.Q.c+@.b z./ (.l l f /./.j j g+j g+U g+'.'.U '.U '.'.'.'.x.. . . ",
+" | y b.b.f.>.x+x -+C.G+c+3.o @.z.w+(.l v+v+$+j $+j g+}+g+U U U '.U '.'.2 '.'.2 '.x.. . . ",
+" L.g.b.b.]+>.c.C+K.Y C.G+c+3.,+b E+%+l 8+8+$+v+$+j F g+U U U U U U '.U U U '.U U '.U x.. . . ",
+" | b.y .+, f.E.A x Y A.0+Q.O.@.f+E+E+w+%+-.8+$+$+j j }+g+j g+U U '.g+'.'.'.U 2 '.U 2 '.2 x.. . . ",
+" 5.g.y b..+f.>.A C+K.Y n+G+c+3.,+E+E+(.%+l 8+/././.$+j U g+U U '.'.U '.U U '.'.'.2 '.'.U '.'.x.. . . ",
+" .+b..+, u u Z.C+K.Y C.G+c+p+o @.E+z.(.(.l l v+j j j j j U U U g+U U '.'.U U U U '.U '.2 '.2 2 x.. . ",
+" b.b.b., f.>.x+C+K.Y A.0+G+c+,+,+b z.w+w+l l /.$+$+$+g+g+U g+g+g+U g+U U U U U U U U U U U U '.'.U x.. . ",
+" W .+]+]+u >.A C+x -+A.G+Q.3.3.,+@.b z.%+l /.y.K r+j $+r+j j j j j U j j j j U g+g+j g+j j g+j U U U U 2 x.. ",
+" f.f.u >.x+A C+K.Y A.C.G+c+c+O.@.b E+(.(.l ! h.& +_ }+j g+g+U }+g+j j j j j j j j j }+F F }+F j F g+F U . . ",
+" L.>.>.A c.[.< < q+e N ] D.U.T S.u+'+'+k d+P.s _.O m I *.r+j /.j /.$+j j j $+/././.r+/././.j /.}+j }+}+g+}+U 2 . ",
+" b Z.[.A @ ( o+o+o+N.N.4.n <+<+{+{+Q Q Z 9+g G _.D+O X.S 6 K /.$+$+j /././././.$+/././././.$+/.$+/.K $+j r+j F F V.. ",
+" h x K.x L.^ B.m+m+m+m+X X w.d r.L 8.|+> 1.1.D+O O O X.X.!+p /./.f /.f /.f /.-././.l /./.-./.-./././.K /.r+/.K }+F 2 ",
+" K.-+-+Y N &. .b+b+n 4.<+$ 2.t.Q Q Q ;+Z 9+4 M._.X.X.X.} 6 +.v+v+/./.v+-.-.l v+l -.f l -./.-./.f f -.f /./.$+$+}+K V. ",
+" ! Y 5+C.0+0+h ] D.W W !.| | | E '+k h+d+d+2+>+P.^+m X.X.I.; /.-.l l -.l l -.(.)+l (.-.l (.l M l l -.l -.-.-./.f r++.}+H. ",
+" 0+G+0+Q.G+c+c+c+3.O.o @.@.E+E+k w+w+l l v+f /.f P.n.I.G.G._+P.-.-.%+%+%+l %+l (.(.l (.(.l (.l M (.-.-.-.-.-.-.-.-./.* . ",
+" H.Q.c+Q.c+q 3.O.3.3.@.b b b z.w+w+l %+l f l l v+f v+>+P.I C } B ! M (.(.(.(.(.(.(./ (.(.F.(./ (.(.(.(.(.%+l -.-.-.-.f -.K H. ",
+" k O.3.3.,+,+O.@.@.b b E+E+/ w+(.%+%+l f v+/./.f l -.l l P.n.C C B ! l (.(.(.(.(.(.k / / (./ k / (./ (.(.(.M (.l l -.-.f * . ",
+" F.@.o ,+,+@.@.E+j+E+E+w+z.(.%+l l 8+8+f 8+8+l v+l l -.l l ! _+C ~.B ! / / / E+E+/ E+E+P E+E+E+F.F.F.F./ F.(.k M )+-.-.)+f K ",
+" @.b b j+j+b b E+z.z.z.w+%+l l l l /./.v+/.f f l f l l (.(.%+t o.C ~.B d+k E+F.E+f+b b E+b j+F.j+F.E+F.F./ F./ (./ (.M -.-.f ",
+"$+E+E+z.z.w+w+z.w+w+(.%+l %+l 8+/.8+v+f v+l l -.l l l l (.(.(.(.=.o.#+~.B |.E+f+F.j+j+E f+E f+f+f+E j+f+b F.E+F.(.F.(.M M M M -.",
+"f w+w+w+w+w+w+(.(.%+l l l l 8+f 8+/././.-././.8+-.l (.(.(.(.(./ z.H B 9 9 B # '+f+f+o o o f+o f+f+f+f+E j+E E f+P / F.F.(.M l -.",
+"8+%+%+%+%+%+l l l l l l v+f v+$+/.$+v+v+v+l l l l -.(.(.w+/ z.F.E+F.|.B <.9 r m.i S.,+o O.O.O.O.o O.o O.f+f+P b b F.F./ (.k M )+",
+"-.l l l l l 8+8+>+>+>++.>++.p p y.+.p p 2+P.2+2+d+k 2+%+F.E+/ j+f+j+F.- v #+~+z (+i ) | u+u+u+J a.5.| u+J J a+J J :+k F.F./ (.M ",
+"8+8+8+v+/.l /.K + g d.6.6.6.[+& & & R !+R !+!+!+!+!+k.M (.E+F.E+E f+'+w 9 #+~+#+<.0 0 0 j.j.j.j.v u.++++/+~ l.1 l.l.= %.F./ (.(.",
+"$+/./.f 8+$+v+y.g 1.1.s.s.O O O X.X.X.X.&+&+&+&+T.G.@+z+E+P E+j+f+f+u+}.#+~+#+#+Y.#+Y.R.Y.R.R.R.R.R.R.v.v.' ' ' ' ' l.i P F.F.M ",
+"$+$+j j /.$+/.r+e.6.d.[+[+[+R R R !+!+R !+@+@+@+!+@+[ '+E+j+f+j+o o J m.<.#+#+#+z 0 0 j.j.j.++++~ /+~ ~ l.l.l.1 1 /+w i f+P P F.",
+"j v+/.$+j j $+}+*.4+*.4+4+*.4+y.4++.>+p >+! M d+d+h+'+(.F.f+f+f+@.O.O.^.(+<.#+R.(+7.k+7 6+7 % !.!.7 !.A+!.A+A+A+7.^.!.f+E b b (.",
+"F g+j j $+g+j j j j }+j g+U j j $+/./.-.-.-.(.(./ (.E+E+E+P f+o o O.O.6+^.w 0 w 7.5 G+V G+J.V J.V J.V 5 J.5 6+p+q 6+..O.o E E F.",
+"U j j g+g+}+g+}+U g+U U }+g+U j K j v+/.l l l (.(.E+F.E f+f+O.O.O.p+p+..6+7 7 !.J.V V V ` n+l+l+l+V J.J.5 J.5 6+....O.o O.E E F.",
+"U F j }+U j g+g+F g+g+U U g+F g+$+$+/./.-.(.(.(.(.E+E+E+f+f+@.O.O.q q 5 q 5 5 l+l+l+n+5+5+V 5+` l+5+l+` V V V J.6+6+6+O.O.o o E ",
+"'.U g+U g+F U F U U U U F U j }+/./.f l l l l (./ F.F.f+f+o O.O.p+p+p+q J.J.l+G+` n+l+l+n+5+5+5+5+n+3 5+l+G+J.5 J.5 p+....1+S.F.",
+" U g+U U g+U U g+U '.U U U j F $+/./.f -.(.(.k / E+j+f+f+o o O.p+q 5 5 G+J.V l+5+3 5+5+e e 5+e @ 5+5+` 3 l+n+J.J.J.6+..O.o O. ",
+" U U g+U U U g+U g+g+U F g+U j j $+f -.l l w+w+z.F.E+j+@.o O.q q 5 5 l+V l+n+n+n+5+e @ a @ a @ 5+5+5+5+5+3 V V J.5 5 q 6+O.o ",
+" . 2 g+'.g+U U U U U '.'.F j }+/./.v+-.(.l (./ E+b E o S.O.O.O.q q 5 5 V l+5+5+e @ 5+5+a @ a K.@ @ a 5+5+5+5+V V J.% 5 6+O.%. ",
+" V.U '.U U '.'.'.'.'.U U U U $+j /./.8+-.(.(.k / P f+@.o o p+q q 5 J.l+n+3 5+5+5+5+a {.@ a @ i.{.K.@ @ e 5+` 5+V V J.6+6+) *. ",
+" 2 U '.U U 2 t+t+c t+W.*.*.4+*.p ! 2+2+M h+'+z+%.'+f+O.o p+p+q 5 J.l+l+l+5+5+a @ @ K.i.{.{.{.i.{.K.@ e @ 5+n+V J.J.5 ..O. ",
+" x.'.U '.'.t+[ @+,.: : D : D @+: e+D D }.e+7+D 7+9.E o O...q 5 5 G+J.` 5+5+a @ {.a {.{.q.{.{.{.{.i.{.a 5+e 3 ` l+V % % p ",
+" x.U U '.].,.T.T.T.T.G.T.G.=+=+=+=+~+=+=+~+~+~+0 u+O.O.p+q q 5 l+l+n+5+5+e @ i.{.{.{.{.8 8 8 8 {.i.K.@ e 5+3 V J.J.% ",
+" 2 '.'.U H.[ @+@+D D : y+D @+D y+}.e+0 0 }.0 0 9.a+o O...q J.J.J.V 5+n+5+a a a {.{.8 8 8 8 8 {.i.{.i.@ @ 5+l+l+V 5 J ",
+" . 2 '.'.'.H.].].].c ].*.*.p p +.! 2+M M h+%.%.J f+O.O.p+p+5 V G+V 5+5+5+e @ @ {.{.8 8 3+8 3+8 8 {.a @ @ e ` ` J.J.1+ ",
+" 2 2 2 2 '.2 '.'.U F F }+$+/.-.f -.%+k / F.E j+o o O...5 5 5 V l+` 5+5+@ K.{.{.{.8 3+8 3+8 8 {.i.i.@ e 3 5+V V p. ",
+" x.'.U '.'.'.'.U F g+}+}+$+-.-.M (.(.z.E+b f+f+O.O.O.q q J.J.l+` 5+5+@ @ {.{.{.{.8 [.E.8 8 {.{.a @ @ 3 n+` % ",
+" x.U '.'.U U '.'.U }+j j /./.-.l -.(./ / P f+f+o O.q p+5 5 V V l+5+5+5+@ @ {.{.8 8 8 8 8 {.{.@ @ @ 5+n+3 V ! ",
+" . U 2 2 U 2 U '.F }+j /././.l M M k E+F.f+f+o o O.q q q J.V ` 5+e 5+a @ {.{.{.8 {.8 8 8 {.{.@ e 5+` V J. ",
+" 2 '.'.2 U F+U F }+K j /.-.-.l %+(.(.E+P f+o O.O.O.5 5 5 l+l+V 5+e 5+@ @ a {.{.{.{.{.a i.@ @ @ 5+3 V ",
+" . V.'.F+2 '.U F F r+$+/.-.-.(.(./ F.F.P f+f+O...O.q q q J.l+V l+5+5+5+@ @ @ {.@ @ i.@ @ e 5+3 l+J.1+ ",
+" . 2 2 F+U '.U }+j /././.-.-.M (./ F.E+F.E o o ....% J.5 J.l+5+` 5+5+5+5+@ @ a @ a @ e @ 3 5+` ! ",
+" . . 2 2 '.'.F F r+/././.l )+M (.F.j+j+E S.O.O.O...5 5 J.J.V V 5+5+e 5+5+@ @ 5+e @ 5+e ` V ) ",
+" V.x.'.'.U }+}+j $+/.-.f l %+(.k F.b j+f+f+O.O.p+6+% 5 J.V n+` ` 5+5+3 5+5+e 5+n+` V V ! ",
+" . #.'.'.U F }+r+/.-.-.-.(.(.k / F.P f+f+O.O.O.3.6+% Q.% J.V V ` n+` ` 3 3 3 5+` V 1+ ",
+" 2 U F }+}+j $+/.-.-.-.M (.F.F.E+P E o O.......p+% Q.5 5 J.J.V V V l+V V V V ",
+" . F+F }+}+r+$+-.-.l M (.(.F.F.P b E f+O.O.......% 5 5 5 J.J.V J.J.J.% 1+ ",
+" U F }+j K /.f -.-.-.(.k F.F.P F.E E o O.O.6+q 6+% 5 5 5 5 J.5 % ",
+" H.}+}+r+/./.f )+M (.(./ F.P j+f+E f+o o O...k+6+6+6+6+% 6+O. ",
+" U }+K -.-.-.M M k (.F.F.P E E S.O.o O...O.....E ",
+" t+* /.f -.l M (.F.k E+E j+E E E f+O.%.P ",
+" -.-.M )+(./ k F.F.F.E E "};
diff --git a/arts/builder/pics/Synth_MOOG_VCF.xpm b/arts/builder/pics/Synth_MOOG_VCF.xpm
new file mode 100644
index 00000000..7f9662c3
--- /dev/null
+++ b/arts/builder/pics/Synth_MOOG_VCF.xpm
@@ -0,0 +1,305 @@
+/* XPM */
+static char * Synth_MOOG_xpm[] = {
+"64 64 238 2",
+" c None",
+". c #161E54",
+"+ c #4A962C",
+"@ c #3A5A6C",
+"# c #2E4254",
+"$ c #5ACA1C",
+"% c #3A4E74",
+"& c #6A7694",
+"* c #52AE24",
+"= c #3A427C",
+"- c #222E64",
+"; c #66E614",
+"> c #4E6E7C",
+", c #263664",
+"' c #464E8C",
+") c #4E5A9C",
+"! c #32466C",
+"~ c #7E86AC",
+"{ c #8692B4",
+"] c #5EDA14",
+"^ c #6EF614",
+"/ c #4E629C",
+"( c #2E3E74",
+"_ c #56BE1C",
+": c #3A4A74",
+"< c #2E3674",
+"[ c #3E4E84",
+"} c #767EA4",
+"| c #62D21C",
+"1 c #7EFE1C",
+"2 c #222E74",
+"3 c #46568C",
+"4 c #969ECC",
+"5 c #323E84",
+"6 c #1A2664",
+"7 c #6A76BC",
+"8 c #5AB62C",
+"9 c #72FE14",
+"0 c #5A62AC",
+"a c #4EA22C",
+"b c #5E6AB4",
+"c c #565EA4",
+"d c #868EB4",
+"e c #8E9ABC",
+"f c #3A467C",
+"g c #2A3674",
+"h c #4E5E94",
+"i c #5AC61C",
+"j c #3A4A8C",
+"k c #425684",
+"l c #7276A4",
+"m c #5AAE2C",
+"n c #5662A4",
+"o c #36427C",
+"p c #2E367C",
+"q c #425284",
+"r c #66D224",
+"s c #222A64",
+"t c #465A8C",
+"u c #2A3E64",
+"v c #62CA2C",
+"w c #3A5674",
+"x c #52B21C",
+"y c #223264",
+"z c #6AEE14",
+"A c #2A3A64",
+"B c #46528C",
+"C c #7E8AA4",
+"D c #8E92C4",
+"E c #62E214",
+"F c #76FA14",
+"G c #324274",
+"H c #2A3274",
+"I c #4E5694",
+"J c #3E4E74",
+"K c #36467C",
+"L c #5EC22C",
+"M c #324284",
+"N c #4EAA24",
+"O c #6672BC",
+"P c #3A468C",
+"Q c #32426C",
+"R c #162254",
+"S c #4E9E2C",
+"T c #6E76A4",
+"U c #6EE624",
+"V c #4E727C",
+"W c #2A3664",
+"X c #4E5AA4",
+"Y c #66DA24",
+"Z c #6EFA14",
+"` c #52669C",
+" . c #323E74",
+".. c #5AC21C",
+"+. c #3A4A84",
+"@. c #424E94",
+"#. c #7E82B4",
+"$. c #5ED614",
+"%. c #263274",
+"&. c #4A569C",
+"*. c #1E2A6C",
+"=. c #7AFE14",
+"-. c #666EB4",
+";. c #525EA4",
+">. c #424A94",
+",. c #2E3A7C",
+"'. c #4A5A9C",
+"). c #2E426C",
+"!. c #46529C",
+"~. c #7E8AB4",
+"{. c #4A9A2C",
+"]. c #5ECE1C",
+"^. c #365264",
+"/. c #6E7694",
+"(. c #56AE2C",
+"_. c #3A428C",
+":. c #262E6C",
+"<. c #364A74",
+"[. c #8A96BC",
+"}. c #62DE14",
+"|. c #5ABE2C",
+"1. c #2E3A6C",
+"2. c #424E8C",
+"3. c #7A82AC",
+"4. c #86FE1C",
+"5. c #4A5694",
+"6. c #9AA2CC",
+"7. c #1E2664",
+"8. c #6E7ABC",
+"9. c #3E626C",
+"0. c #56BA1C",
+"a. c #62CE24",
+"b. c #6AEA14",
+"c. c #5A66AC",
+"d. c #626EB4",
+"e. c #727AA4",
+"f. c #6EF214",
+"g. c #56AA2C",
+"h. c #4EA624",
+"i. c #5666A4",
+"j. c #8E96BC",
+"k. c #3E5274",
+"l. c #6EEA24",
+"m. c #526E8C",
+"n. c #5EC62C",
+"o. c #1A2264",
+"p. c #52728C",
+"q. c #62D624",
+"r. c #3A5274",
+"s. c #425294",
+"t. c #222A74",
+"u. c #56BA2C",
+"v. c #525A94",
+"w. c #8A92BC",
+"x. c #8A8EBC",
+"y. c #929AC4",
+"z. c #3E4684",
+"A. c #525E9C",
+"B. c #3E4A8C",
+"C. c #6AD224",
+"D. c #4A5A8C",
+"E. c #2E3E64",
+"F. c #56B224",
+"G. c #263264",
+"H. c #364284",
+"I. c #1A225C",
+"J. c #62D61C",
+"K. c #323A84",
+"L. c #5ECA1C",
+"M. c #36466C",
+"N. c #62DA14",
+"O. c #72F614",
+"P. c #52629C",
+"Q. c #5ABE1C",
+"R. c #82FE1C",
+"S. c #262E74",
+"T. c #9A9ECC",
+"U. c #363E84",
+"V. c #76FE14",
+"W. c #626AB4",
+"X. c #5EC61C",
+"Y. c #66E214",
+"Z. c #3E468C",
+"`. c #525AA4",
+" + c #72FA14",
+".+ c #3E4A84",
+"++ c #4A529C",
+"@+ c #828AB4",
+"#+ c #4E9A2C",
+"$+ c #66CE24",
+"%+ c #5E66AC",
+"&+ c #767AA4",
+"*+ c #52AE2C",
+"=+ c #3A4284",
+"-+ c #222E6C",
+";+ c #26366C",
+">+ c #464E94",
+",+ c #7E86B4",
+"'+ c #2E3E7C",
+")+ c #3A4A7C",
+"!+ c #3E4E8C",
+"~+ c #767EAC",
+"{+ c #465694",
+"]+ c #868EBC",
+"^+ c #8E9AC4",
+"/+ c #3A4684",
+"(+ c #2A367C",
+"_+ c #4E5E9C",
+":+ c #5662AC",
+"<+ c #42528C",
+"[+ c #66D22C",
+"}+ c #222A6C",
+"|+ c #52B224",
+"1+ c #2A3A6C",
+"2+ c #465294",
+"3+ c #7E8AAC",
+"4+ c #76FA1C",
+"5+ c #32427C",
+"6+ c #2A327C",
+"7+ c #4E569C",
+"8+ c #364684",
+"9+ c #2A366C",
+"0+ c #5266A4",
+"a+ c #323E7C",
+"b+ c #26327C",
+"c+ c #7AFE1C",
+"d+ c #2E3A84",
+"e+ c #6E769C",
+"f+ c #2E3A74",
+"g+ c #1E266C",
+"h+ c #6E7AC4",
+"i+ c #4EA62C",
+"j+ c #8E96C4",
+"k+ c #3E4A94",
+"l+ c #4A5A94",
+"m+ c #2E3E6C",
+"n+ c #26326C",
+"o+ c #36428C",
+" %.H H 6+6+%.S.2 t.}+*.7. ",
+" s f+H.H.K.d+,.(+b+S.%.S.2 2 }+2 o.. . . ",
+" < .+>.Z._.H.5 d+p p (+b+%.S.t.2 *.*.*.g+o.o.. . ",
+" 1.) 7+5.>+>.P o+U.K.d+,.(+b+S.2 2 2 t.2 2 t.*.*.6 o.. . . . ",
+" v.c ;.7+++@.k+P o+M K.p (+(+(+6+%.S.2 t.*.*.*.*.t.*.*.g+g+o.. . ",
+" I W.%+:+`.7+2+@.>.Z.o+U.5 d+p 6+%.%.S.2 -+2 t.t.t.g+*.*.g+*.g+*.o.. . . ",
+" d.d.b 0 c X &.>+>.Z.P o+5 K.d+p 6+b+b+S.S.t.-+*.*.t.g+*.*.g+*.g+*.g+6 o.. . ",
+" ' 7 O W.c.:+;.X &.!.k+j _.U.K.'+,.(+(+H %.%.2 2 t.2 t.*.t.g+g+*.g+*.g+g+g+g+o.. . . ",
+" = T O O W.c.n `.&.++>+>.Z.P H.K.d+,.(+b+b+S.2 S.2 t.-+t.*.*.*.g+*.g+g+6 g+g+6 g+o.. . . ",
+" I 8.O O W.c.0 ;.) &.2+@.B.P o+U.5 p (+6+6+S.b+S.2 }+t.*.*.*.*.*.*.g+*.*.*.g+*.*.g+*.o.. . . ",
+" = T 7 -.d.b c.c `.7+!.@.k+Z._.o+5 5 d+p g 6+S.S.2 2 -+t.2 t.*.*.g+t.g+g+g+*.6 g+*.6 g+6 o.. . . ",
+" ' 7 O O -.b c.c ;.X &.!.@.k+P H.5 5 ,.p (+6+%.%.%.S.2 *.t.*.*.g+g+*.g+*.*.g+g+g+6 g+g+*.g+g+o.. . . ",
+" O 7 -.d.%+c.:+;.X &.!.>+>.B.P o+5 K.,.,.(+(+b+2 2 2 2 2 *.*.*.t.*.*.g+g+*.*.*.*.g+*.g+6 g+6 6 o.. . ",
+" O O -.6.T.c.0 ;.X &.++>+!+B._.o+U.K.d+d+(+(+%.S.S.S.t.t.*.t.t.t.*.t.*.*.*.*.*.*.*.*.*.*.*.*.g+g+*.o.. . ",
+" .+-.-.W.4 4 c ;.`.7+!.>+>.Z.P _.H.U.K.p (+6+6+%.%.2 S.:.2 2 2 2 2 *.2 2 2 2 *.t.t.2 t.2 2 t.2 *.*.*.*.6 o.. ",
+" W.W.c.c.:+;.;.`.&.++!.@.>.j P H.U.5 ,.,.(+(+%.b+S.S.2 2 t.t.*.-+t.2 2 2 2 2 2 2 2 2 -+}+}+-+}+2 }+t.}+*.. . ",
+" I c.0 :+:+c X X 7+{+>+@.k+Z.P _.5 5 K.p p (+6+%.b+%.2 2 S.2 %.2 %.S.2 2 2 S.%.%.%.:.%.%.%.2 %.-+2 -+-+t.-+*.6 . ",
+" U.0 c :+Z.`.j+j+&.!.>+@.k+k+P _.5 U.,.,.,.(+%.%.%.S.2 %.S.%.%.S.S.2 %.%.%.%.%.S.%.%.%.%.%.S.%.S.%.n+S.2 :.2 }+}+I.. ",
+" ' ;.X ) /+&.D w.!.@.>.k+P _.o+o+5 K.d+(+(+(+6+b+%.%.S.%.%.%.%.%.H %.H %.H %.g %.%.(+%.%.;+%.;+%.%.%.n+%.:.%.n+-+}+6 ",
+" X 7+7+7+_.++{ ]+@.>.k+Z._.o+U.5 K.d+p p 6+6+%.H b+H %.%.%.%.%.b+b+%.%.9+;+).%.(+g H (+(+H (+6+H 6+;+H %.%.S.S.S.y I. ",
+" W ++!.!.>+U.>+]+@+k+Z._.P =+U.K.'+K.,.(+(+H 6+%.%.b+(+H 6+6+(+g g (+H , h.].u.W g ,.g (+,.g 1+(+g (+(+g g ;+%.%.S.H -+6 ",
+" >+s.>+@.@.!+k+Z.Z.P 8+=+U.5 5 a+d+,.(+(+H b+;+6+6+%.%.(+%.(+H (+(+g A * +9 ^ h.g (+,.,.(+,.p ,.,.< g g (+g g g g n+- . ",
+" 7.>.k+k+k+Z.Z.Z.Z._._.o+U.5 5 K.p (+p (+6+g 6+b+H (+(+%.(+H (+(+g (+, * ^ Z J.^ ].A f+,.a+,.'+,.f+,.,.,.< p < g g g H 9+n+7. ",
+" K.P Z.Z._.P d+8+,+,+U.5 5 5 d+p ,.p 6+6+;+b+%.H (+(+H (+(+,.,.(+,.A * ^ ^ g.# ].^ i+1+'+,.a+K.'+,.'+,.,.,.f+,.(+< g g H :.. ",
+" .o+o+_._.U.p o+,+,+5 K.K.p d+p (+(+H 6+6+6+(+%.6+(+(+(+(+(+,.(+A F.O.Z * u 1+i+^ ].1.a+a+a+a+5 a+a+a+'+'+,.f+,.p < g g H G. ",
+" U.H.U.M 5 5 H K.#.3.d+,.(+,.(+6+(+%.b+%.%.(+%.(+(+g p ,.p ,.,.u *+^ Z *+u '+a+E.$ f.i+).5 M U.5+5 5 a+5 a+a+a+f+'+,.f+g 9+H ",
+"%.5 5 K.5 5 d+%.,.~+3.,.p (+(+(+%.6+%.b+H %.(+g (+(+(+g ,.,.,.^.n. +O.*+m+5 5 M G h.f.L.).a+M H.o o M o 5 a+5 a+,.'+,.,.,.1+1+g ",
+"H d+d+d+p d+,.,.d+,.p (+(+6+H %.6+%.%.%.(+6+6+(+g (+,.,.,.1+u L +O.|+E.a+U.H.H.H.m+$ z a o /+H.H.H.H.H.o M o M 5+a+a+a+,.,.p g ",
+"H p p d+p p p (+6+6+6+(+b+b+%.S.S.S.S.%.%.;+6+(+,.g 1+1+A N | + +*+m+5 H.8+H.H.8+o h.z $ ).K 8+8+/+8+8+H.H.o U.a+a+a+a+K.f+f+< ",
+"6+(+(+6+(+(+6+-+(+} e.n+;+, n+;+;+;+;+n+;+9+9+9+;+A g.a.| 4+V. +*+m+5+8+8+H.8+8+/+8+Q $ b.a o P P /+/+/+/+8+H.K H.o a+ .a+a+,.1+",
+"6+6+(+b+b+(+b+}+b+~+& m C.C.r $+$+$+r r $+a.$+a.a.J.O.c+V.V.U L E.U.H.H.8+_./+8+P P f h.z L.! +.j P /+/+/+/+H.8+H.H.M 5+a+a+K.,.",
+"S.%.S.%.%.S.%.}+%.&+& C.4.4.4.R.R.R.1 1 1 1 =.=.=.c+V.l.U [+@ r.H.8+H.8+P +.P B.B..+/+! i b.a f B.+.j j +.j +./+8+8+o U.5+a+a+f+",
+"S.b+S.S.b+S.%.}+2 e.& g.r $+r C.r $+$+a.a.a.a.a.].v |.9.r.r.M M H.8+P 8+P j +.j !+!+B.)+a b.i M.B.!+!+B.+.Z.+./+/+/+8+o o 5+5+a+",
+"2 2 S.S.2 2 2 2 2 t.t.y y y - - - , , , W A 1+1+1.m+m+'+5+5 M 8+8+P /+j +.B.B.!+B.B.!+>.M.i ; a % 2.B.!+B.[ B.+./+8+8+H.o U.U.,.",
+"t.2 2 2 S.t.t.2 S.2 t.}+t.-+-+-+-+2 %.;+(+g (+,.,.K.a+5 H.H.H.o+/+P P P j j B.!+!+2.<+<+)+a ; ..<.2.!+2.B.B.!+B..+z.+.8+8+o o a+",
+"}+2 2 t.t.S.2 *.-+l e.*.-+t.*.2 S.%.H 6+6+(+,.(+,.'+5 a+M H.=+/+8++.B.B.B.!+!+!+s.s.@.<+<+% i ; S [ <+<+<+2.>.[ B.+./+/+f H.o a+",
+"g+}+-+-+*.t.}+g+}+T e.*.*.t.}+2 2 2 %.;+(+(+,.,.'+K.M a+H.8+8+P P j +.!+!+2.@.2.<+<+s.2+2+[ a ; ..: 2.s.<+<+!+[ B.B.j /+/+8+K o ",
+"*.*.t.*.t.*.*.g+*.l l *.*.*.2 -+S.%.b+6+g (+,.,.K.a+a+H.H.H._.+.+.j !+!+@.!+<+s.s.{+2+{+3 3 % ..E S q s.<+<+<+2.!+[ .++.+./+=+a+",
+" *.t.*.t.t.*.*.*.T l t.}+*.t.-+S.%.;+(+g (+,.,.'+5 5 M H.8+P P Z.B.B.!+s.@.<+2+s.{+{+{+5.5.q a E _ J {+2+B s.<+!+!+B.+./+8+/+ ",
+" *.*.*.*.*.*.g+t.}+*.g+*.}+-+2 2 S.H H p ,.,.'+5 a+H.H.8+8+8++.j B.!+!+2.<+2+s.{+{+{+{+'.t {+k...E S q {+s.<+' 2.2.!+.+.+/+K ",
+" . g+*.g+t.*.*.*.g+*.g+*.*.2 S.%.%.(+;+(+,.,.,.5 a+H.H.=+P P +.!+B.@.s.s.<+{+{+5.5.'.5.'.'.) t 8 E _ % 3 {+{+2+<+2.!+!+.+/+ . ",
+" I.*.*.*.*.*.6 g+l T *.g+t.}+-+S.S.%.(+(+(+,.a+a+M M H.8+/++.B.j !+!+2.<+2+{+5.{+'.t _+) _+l+l+> Y }.S k 5.{+k <+<+2..+.+f - ",
+" o.*.g+g+g+6 *.l T *.g+*.2 2 %.%.%.g ,.p ,.'+a+U.H.H.8+P j B.!+2.!+s.s.2+2+5.t '.'.l+_+_+_+_+m.v E 0.J {+5.2+<+2.2.!++.z. ",
+" o.g+*.*.*.g+g+e+l g+*.t.*.-+2 S.H (+g ,.,.K.5 5+M 8+_./+/+B.B.!+s.2.3 {+{+'.&.) '._+_+A.P._+h V J.N.S q {+{+2+<+<+[ [ G. ",
+" o.g+g+*.6 *.e+T g+*.}+t.:.%.%.H (+g ,.'+K.a+H.H.8+/+j +.B.!+2.s.s.2+{+{+l+l+h _+_+/ _+P.P.A.m.v }.0.J 3 {+{+<+2.2.2. ",
+" 6 *.*.6 *.g+g+6 *.*.*.-+2 2 b+;+H ,.,.,.'+5 a+H.H.8+/+j !+B.!+2.<+{+{+{+l+'.'._+_+_+P.P.P.P.P.V | ] {.q 3 <+<+<+[ = ",
+" . o.g+g+g+6 *.6 g+*.}+-+S.n+%.(+%.g ,.,.,.5 a+H.8+/+/+P !+!+<+@.<+<+{+{+l+) l+_+A.P.0+0+0+i.P.m.n.}.0.J {+2+B 2.[ z. ",
+" g+*.g+6 g+T l 6 g+*.*.-+2 %.%.(+(+< a+a+a+M H.H.H.P +..+>.!+<+s.{+{+&.t '.h _+/ / P.P.i.P.P._+> L.$.{.q 3 <+<+: ",
+" o.g+g+g+T l *.g+}+2 :.S.%.%.g ,.(+,.a+a+5+H.8+8+P j +.B.2.2.@.B {+5.l+'.l+_+A./ P.P.0+P.P._+h {.F.+ q s.B 2. ",
+" o.6 6 7.e+e+e+l *.*.l e.&+~+;+g 3.3.3.#.5 H.,+~ @+@+B.!+d { w.{ {+{+w.j.j.j._+A.y.^+y.^+_+h [.C C ~ <+3 <+W ",
+" o.g+g+T T e+l }+-+e.e.} &+b+g } 3.~ ~ a+o @+3+~ @+B.B.@+d ]+d 2+{+w.[.[.[._+_+e e e ^+_+) e [.[.w.B B 2. ",
+" 6 6 o.g+6 *.*.*.}+n+S.%.g (+,.1+,.'+5+U.H.H./+/+/+j 2.!+<+s.{+{+{+'.l+) '.h _+_+_+h h h ) l+3 5.3 q ",
+" . o.6 g+o.6 g+*.g+*.-+}+;+(+S.n+H H a+a+1+,.f+,..+j a+a+5+a+<+3 o H.K 8+'.) /+/+/+/+l+l+f f {+2+2.z. ",
+" . g+6 6 g+*.}+-+:.S.%.H %.g (+,.,.'+5 U.H.8+/++..+.+!+2.<+<+s.2+{+{+5.5.l+l+) ) l+l+5.{+{+3 q W ",
+" . I.7.7.*.*.*.-+:.%.g g < g f+a+a+5+a+H.8+H.8+j .+B.B.2.2.<+B B 3 {+{+{+t t l+5.{+{+B 2+<+f ",
+" . 6 6 7.g+-+}+2 :.%.H g p ,.,.'+a+M a+H.8+/+/+P .+[ !+<+<+<+s.2+3 3 5.5.5.{+{+3 3 {+q W ",
+" . o.*.7.*.-+2 :.%.%.;+(+g f+,.a+5+5+H.H.8+/++.j B..+B.2.<+<+s.B <+s.<+B {+{+B <+<+z. ",
+" o.*.}+}+-+-+%.%.g g ,.p f+K.a+U.o o =+8+8+z.+.B.!+!+2.!+2.<+s.B 2+<+<+<+<+' ",
+" R *.*.-+-+%.S.H H g ,.f+,.( a+M 5+o /+8+/++.+..+.+[ !+!+2.!+<+<+2.2.2.)+ ",
+" *.}+}+:.n+%.;+g g ,.f+K.'+a+a+H.H.H./+8+/+P +.B.[ B.[ 2.!+2.!+[ ",
+" 7.*.:.n+%.H %.g < f+K. .a+a+a+o H./+/+/++.+.z..+.++..+.+.+f ",
+" *.:.%.g g g g f+,.a+a+5+o 5+o o 8+/+/++.+.+..+o ",
+" s s ;+g g < f+,.,.'+a+a+H.o o o H./+U.G ",
+" H g g f+f+f+K.a+a+a+U.o "};
diff --git a/arts/builder/pics/Synth_MUL.xpm b/arts/builder/pics/Synth_MUL.xpm
new file mode 100644
index 00000000..9261785e
--- /dev/null
+++ b/arts/builder/pics/Synth_MUL.xpm
@@ -0,0 +1,309 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 238 2",
+/* colors */
+" c #A3A8C1",
+" . c #354280",
+" X c #4E5688",
+" o c #A0A4BE",
+" O c #2F3C7A",
+" + c #1B2463",
+" @ c #3A4888",
+" # c #3E4982",
+" $ c #293474",
+" % c #CDD0E0",
+" & c #626B98",
+" * c #38437C",
+" = c #232E6E",
+" - c #4A5487",
+" ; c #C1C4D4",
+" : c #1C2667",
+" > c #2F3973",
+" , c #3E4B85",
+" < c #2A3678",
+" 1 c #253073",
+" 2 c #35417C",
+" 3 c #202A6E",
+" 4 c #2F3A80",
+" 5 c #1E286C",
+" 6 c #455085",
+" 7 c #1C266A",
+" 8 c #AAAFC7",
+" 9 c #29347A",
+" 0 c #263077",
+" q c #253076",
+" w c #374581",
+" e c #475594",
+" r c #232E74",
+" t c #323F7C",
+" y c #313D7B",
+" u c #576393",
+" i c #3D4B8A",
+" p c #2B3775",
+" a c #BBC0D4",
+" s c #3A4787",
+" d c #4B579B",
+" f c #5C67AF",
+" g c #394786",
+" h c #263170",
+" j c #354382",
+" k c #242F6E",
+" l c #445194",
+" z c #6872B4",
+" x c #38447E",
+" c c #343F84",
+" v c #1D276A",
+" b c #2D377D",
+" n c #C0C3D5",
+" m c #434D82",
+" M c #283378",
+" N c #3A4883",
+" B c #273177",
+" V c #263176",
+" C c #525A8A",
+" Z c #252F75",
+" A c #242F74",
+" S c #455491",
+" D c #35427E",
+" F c #212B71",
+" G c #202B70",
+" H c #6C76AA",
+" J c #404E8C",
+" K c #616CB3",
+" L c #2D3876",
+" P c #555E90",
+" I c #2B3674",
+" U c #3A4886",
+" Y c #374483",
+" T c #A1A6C0",
+" R c #232E6C",
+" E c #313E7D",
+" W c #2D3A79",
+" Q c #3E4A8D",
+" ! c #2A3676",
+" ~ c #384487",
+" ^ c #273273",
+" / c #253071",
+" ( c #414C93",
+" ) c #43518B",
+" _ c #1E286A",
+" ` c #1C2668",
+" ' c #1B2667",
+" ] c #2B367A",
+" [ c #4B5B96",
+" { c #273276",
+" } c #242E73",
+" | c #222C71",
+". c #455390",
+".. c #212C70",
+".X c #202A6F",
+".o c #1F2A6E",
+".O c #1E286D",
+".+ c #3F4D8A",
+".@ c #2F3B77",
+".# c #3E4D89",
+".$ c #3E4B89",
+".% c #4C599A",
+".& c #384583",
+".* c #283370",
+".= c #3C467D",
+".- c #555FA6",
+".; c #424F90",
+".: c #212B69",
+".> c #3F4D8D",
+"., c #3E4D8C",
+".< c #333C74",
+".1 c #2D3978",
+".2 c #4F59A0",
+".3 c #6E759A",
+".4 c #2C3777",
+".5 c #2B3776",
+".6 c #485399",
+".7 c None",
+".8 c #263171",
+".9 c #DCDEE8",
+".0 c #212B6C",
+".q c #313B7F",
+".w c #9A9FBB",
+".e c #3F4B90",
+".r c #283376",
+".t c #4A5A94",
+".y c #263174",
+".u c #394680",
+".i c #354186",
+".p c #182059",
+".a c #232D71",
+".s c #45548F",
+".d c #323D83",
+".f c #7279A4",
+".g c #2E397F",
+".h c #C1C5D7",
+".j c #1D276B",
+".k c #404E8A",
+".l c #3E4C88",
+".z c #2A357B",
+".x c #29357A",
+".c c #9399B7",
+".v c #283379",
+".b c #3B4885",
+".n c #263177",
+".m c #475694",
+".M c #5862A8",
+".N c #777EA2",
+".B c #435290",
+".V c #33407D",
+".C c #435090",
+".Z c #41508E",
+".A c #3E4C8B",
+".S c #3C4A89",
+".D c #2B3675",
+".F c #293473",
+".G c #384685",
+".H c #8E95B5",
+".J c #273271",
+".K c #B7BBD0",
+".L c #CBCEDD",
+".P c #354282",
+".I c #1F2A69",
+".U c #1E2868",
+".Y c #3D488D",
+".T c #384288",
+".R c #4A5993",
+".E c #C6CADB",
+".W c #353F7B",
+".Q c #B0B5CC",
+".! c #AEB3CA",
+".~ c #414F8A",
+".^ c #1C2669",
+"./ c #2B367B",
+".( c #8087AA",
+".) c #293479",
+"._ c #283278",
+".` c #2B3571",
+".' c #273277",
+".] c #4A5996",
+".[ c #263076",
+".{ c #253075",
+".} c #7B81A5",
+".| c #242E74",
+"X c #232E73",
+"X. c #465592",
+"XX c #222C72",
+"Xo c #212C71",
+"XO c #445390",
+"X+ c #202A70",
+"X@ c #1F2A6F",
+"X# c #42518E",
+"X$ c #495181",
+"X% c #2F3B78",
+"X& c #3C4988",
+"X* c #D0D3E1",
+"X= c #A6ABC5",
+"X- c #4E5C93",
+"X; c #4C5A91",
+"X: c #344180",
+"X> c #323F7E",
+"X, c #222D6B",
+"X< c #2E3B7A",
+"X1 c #6C7399",
+"X2 c #293575",
+"X3 c #B3B8CE",
+"X4 c #222D6E",
+"X5 c #434D95",
+"X6 c #878EB0",
+"X7 c #20296C",
+"X8 c #5C6693",
+"X9 c #333E78",
+"X0 c #2F3B7E",
+"Xq c #1E296A",
+"Xw c #1D2769",
+"Xe c #2C377B",
+"Xr c #3B458D",
+"Xt c #293378",
+"Xy c #495894",
+"Xu c #485893",
+"Xi c #242F73",
+"Xp c #353F87",
+"Xa c #475692",
+"Xs c #232D72",
+"Xd c #222D71",
+"Xf c #455490",
+"Xg c #212B70",
+"Xh c #202B6F",
+"Xj c #43528E",
+"Xk c #C3C7DA",
+"Xl c #1F296E",
+"Xz c #42508D",
+"Xx c #1E296D",
+"Xc c #41508C",
+"Xv c #D4D6E4",
+"Xb c #4E5C9C",
+"Xn c #E6E7EF",
+"Xm c #3A4885",
+/* pixels */
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7 1 {XtXt._ 0 Z r F 3Xq :.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7 I y.TXp.d 4 b.z 9 B q ZXsXXXo GX+Xl + +.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7X&X5 (.Y.TXp.d 4 b.z 9 B q ZXsXXXo G.XX@XlXl 5 +.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7 x.2.2.6X5 (Xr.TXp.d 4 b.z.v B q.|XsXXXo G.XX@XlXx.O.O 5.^ +.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.M.M.-.2.6X5.eXr.TXp.d 4 b.z.v B q.|XsXX F G.X.oXlXx.O 5 5 5.j `.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.% K f.-.2 d.6X5.eXr.TXp.d.g b.z.v.n.{.|XsXX F G.XXlXlXx.O 5 5.j.j.j.^ +.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7 z K f.M.-.2 d.6 (.YXr.T c.d.g b.z._.n Z.|Xs |XgX+.XXlXlXx.O 5 5.j.j.j v v '.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7 ) z z K f.M.-.2.6 l (.YXr.T.d 4.g./ 9._.[ ZX XsXoXg.XX@XlXl.O 5 5 5.j.j v v v v `.p.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7X; z z K K f.-.2 d.6X5.eXr.TXp.d 4 b.z 9.'.[ AX XsXoXg.X.oXlXx.O 5 5.j.j.j v v vXw.^ :.p.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7X- z z z K f.M.-.2 d.6X5.eXr.T c.d 4 b.z.v B q.|XsXX F G.X.oXlXx.O 5 5.j.j.j v v vXw.^.^ :.p.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7X; z z z K f.M.-.2.2.6X5 (.YXr.i c 4.gXe 9._.n Z.|Xs |XgXh.XXlXlXx 5 5.j.j.j v v vXw.^.^.^ ` :.p.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7 ) z z z K f.M.-.-.%.6 l (.YXr.TXp.d 4 b./ 9.'.[ ZX XsXoXg.X.oXlXl.O 5 5 5 v.^.^ ` `.^ ` `.^ ` ` :.p.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7 z z z K f.M.M.-.MXb e.;.eXrXr.T c.d.g b.z.v B.{ AXsXXXo G.X.oXlXlXxXx 5 5.j _.U.U.UXwXw.^ `Xw ` ` :.7.7.7.7.7.7.7",
+".7.7.7.7.7.7 z z K K f.M.M.M &.} H &Xa.$ ~.T c.d 4 b./ 9._ V Z }Xs |Xg G.X.X 3 3 3 3X7Xq.: R.`.<.*.:.U.U v _ _XwXw +.7.7.7.7.7.7",
+".7.7.7.7.7.% K K K f.M.-.- H.(X=.w.H & 6.& c.d.d.g b.zXt.'.[ AX Xs |.................0.0.* *X$X8.=.*.:.IXqXqXqXqXq.U.p.7.7.7.7.7",
+".7.7.7.7.7 K f f f.M.-.2.- HX6X3.Q.Q.(X8 m.V.q.g b./ 9._ V Z.|X XsXsXdXdXd.a.a.aX4X4 R.`.= &.N.HX8.=.*X,.0.0.0.0X7Xq.U.7.7.7.7.7",
+".7.7.7.7.M f.M.M.-.-.2.2Xb H.cXk %Xv.Q.H P x O b ].zXt B.[ Z.| } } }XiXiXiXiXiXi.a k.` mX1 X3XkX6X8.< RX,X4X4X4.0.0.0.U.7.7.7.7",
+".7.7.7 x.M.-.-.-.2.2 d.6XyXb.f T aXv.h.!.} C.= LXt M B V.[.{ Z Z 1 1 1 1 1.y 1 / h >X$X1.H a.KX3.NX$ > k k.a / k =X4X4.0 +.7.7.7",
+".7.7.7.2.-.2.2.2 d d.6 l.C.C u.(X=X*XvXv 8X6 CX9 I { V B V V.y.y.y.y.y { { { ^.J > m.3X= n.9 nX= &.=.` h h /.8 / / k = R.:.7.7.7",
+".7.7.7.2.2 d d.6.6.6X5 (.e Q ) P.NX= aXv aX=.f -.<.J.y V V { { {.'.'.r.r { $.`.<X$.3.c ; ; ;.HX1X$ >.*.J.J $ ^.J.8 / / k =.7.7.7",
+".7.7X&.6.6.6.6 lX5X5 (.eXrXr ~.b P.( X*X*Xv .}X$ >.J { { {.r M MXt.)XtX2 $.<X$.3 8.h.9 ; 8X1 m.<.`.FX2X2X2X2 $.F.J.J h k.U.7.7",
+".7.7X5X5X5X5 ( (.e.e.YXr.T.T cX:.= X.f T.KX*.K .3X$.<.J ^.r M.x.x < ! ! I.<X$.N.c.h.h ;.c.3X$.< > p.5.4.4.4.4 !X2 $.F.J.8 k.7.7",
+".7 I ( (.e.e.Y.YXrXrXr.T.TXp.d.qX0.W X.} TX*X*X* o.NX$ >.FX2Xt.x.x <.4.D.< -.N.!Xk.9 ; 8.3X$.< L.1 W.1 W.1.1.1.4 ! !X2.F.J.J.:.7",
+".7 y.YXrXrXrXrXr.T.T.iXp c.d 4.gXe.1.WX$.3 o.KX*.K oX1X$.< I ! ].4 < >X9 X.N.wXk.h ;.c.3X$X9.@.1 O O OX0 OX< W.1.1.4 !X2 $.F.:.7",
+".7.T.T.T.T.T.T.TXp c c.d.d 4.g b.z.) I >X$.N TX*X* % o.NX$.< p ].4 L.W X.N.Q.E.9 nX=.3X$ * O O E E E E E E y O O W.1.4.5.DX2.*.7",
+".7XpXpXpXpXp c.d.d.d 4 4.g b b./ 9 M ^.J.<X$.3 T.KX*.K oX1X$.W.@.< * C.N.w.EXk n.c.3X$ *X9 EX>X>X:X:X>X>X> E y y OX< W.1 L.DX2.7",
+" 1.d.d.d.d.d.d 4 4 4.g b b./.z 9Xt._ V.y.J >X$.} TX*X* % o.f X * m C.}X3.E.9.hX=.3X$.=.VX>.PX:.P.P .X:X:X:X>X> E y O O W.1 L p.*",
+" { 4 4 4 4.g.g.g b bXe./.z 9Xt._ B V.[.y ^.J.<X$.3 .KX*.K o.NX8.3.( .EXk n.c.3 X.= 2X: j Y Y Y Y Y j.P .X:X:X>X> E y OX%.1 L I",
+"Xt b b b b b b./.z.z 9 9.v._.' V.[.[ V V { {.F >X$.} XvXvX*.K T.QXkX*.9 nX=.3 -.= . j Y.G.G.G.G.G.G.& Y Y j .X:X:X> E y OX%.1 p",
+"Xt.z.z.z.z.z.z 9 9.v._.' B V.[ Z Z.{ V { {.r $ I.< -.N.! ;Xv.L.h.LXv.L.E.c.3 X.= x Y.G s s s s g g g g.G.&.& Y j .X:.VX> y OX% L",
+"._ 9 9.v.v.v._._.' B.n.[.{ Z A.|.| Z.y {.r MXt ! p.< C.H.Q.9XnXnXn.9.E.Q.N X.= w.G g @.S.S.S.SX&X& @ @ s g.G.&.& j .X:.VX> E O.1",
+" 0 B B B B.n.n.[.[ q Z Z A }X X } Z.y { M.x.x ].D.@X$X6 8.9XnXnXnXnXkX=X1 6 # g s.S.S i i i i i i.S.SX&X& U g.G.& Y . D.VX> yX%",
+" Z q q q q.{ Z Z A.|.|X XsXsXsXs } 1.y.' M.x ] ].4 LX$.( 8.9XnXnXnXn n.w & m N @.S Q.A.A.,.,.,.A.A.A.A i.SX& @ U.G.& Y . D.V t O",
+" r Z Z.|.|.|.|X X XsXsXsXX | |Xs } 1.y.'Xt < <.4 >.=X8.w a.9.9XnXnXn.LX3.} P 6 ,.S.A.>.>.>.> J J J J.,.A.A i.SX& U g.& Y . D.V y",
+" FXsXsXsXsXsXsXsXsXX |XoXoXg..XdXi 1.y.r.).).4 p * C.( ;X*Xn.9X*.9XnXv %.w.f C.l.$ J.>.Z.Z.Z.Z.Z.Z.Z.Z J.,.+.A.$X&.b.G.& Y . D t",
+" 3XXXXXXXXXX |XoXo FXgXg G G..XdXi 1 { { !.1X9.=X8.( .LXk a TX6 oX3.hX*X3.w.3 C ).~.Z.Z.B.B.B.B.C.CX#.Z.Z J.+.$.$X&Xm.G.& w D t",
+"XqXoXoXo F FXgXgXg GXh.X.X.X..XdXi 1.y {.4.W -X1.H n.LXv.K.w.NX8.f.H.QXvX*.E.c.f C ) ).BXO S S SXOXOXOXjX#.Z J.+.$.$X&Xm.&.& . 2",
+" : G G G G GX+.X.X.X.X.o.o.X...aXi 1 ^.D * C.3.c.!.L nX3X6 & C m XX8.}.! a %.Q.c.3 P.s. . X. eX.X.X. SXO.B.CXzXc.+.$.S.bXm.& w 2",
+".7X+.X.X.X.X.XX@.o.oXlXlXl 3...aXs 1X2.W C.( T.E %Xv.Q.c & 6 #.&.u #X8X6.!Xv %Xk.c.f P.sXf.m.mXy.m.m.mX. SXOXjXz.~.+.lX&.b.& w.7",
+".7XlX@X@.oXlXlXlXlXlXlXlXl 3XhXd /.F * C.N .K % a.!.( & -.u w g N #X$X8.(X3.hX*.Q.c.3 PX;XuXu.].]XyXy.mX. SXOXjXc.k.#.l.bXm.u.7",
+".7 +XlXlXlXlXlXlXxXxXx.OXx 3Xh =.JX9 C.( .L %X*.!.HX8 m.u Y g @X&.S # mX8.w.K.9 %.h.c.f u.RXy.] [.].]Xy.mX. SXOX#Xc.+.lX&.bX9.7",
+".7 +XlXxXxXxXx.O.O.O 5 5 5XlX4 h.W C.NX=.K.L a 8.(X8 6 x w.G g.S.S i , , C.N.w.E.E.E 8.c.f uX-.t [ [ [.]Xu.mX.. XjXc.k.$X&.bX9.7",
+".7.7 5.O.O.O.O 5 5 5 5 5.jX7 k.< C.(X=.L.L %X=X6X8 # x . Y g @.S.A.A J J.sX8.(.Q n %Xk n.c.f u [ [.%.% [.]XuXa SXOX#.~.#.l N.7.7",
+".7.7 +.O 5 5 5 5 5 5 v.j.I R.< C.}X=.K.L.KX=.} u m 2 D j Y s.S i.A.> J.Z )X; &X6 .hXk.E 8.H.f uX- [ [ [ [XyXuX.XOXj.~.#.l 2.7.7",
+".7.7.7 5 5 5 5 5.j.j 7XwX, > CX6X= %.L.L .( P.= 2X>X: Y.G s.S i.,.>.Z.BXO. X; &X6.KXk %Xk a.H H uXb [Xb [.]XuXaXfXjXc.k.l.7.7.7",
+".7.7.7.^ 5.j.j.j.j.jXw.U > -.NX=.K.LX3 T.N C #X9 yX>.P Y.G s.S i.,.>.Z.BXO SXaX-X1.HX=XkXkXkX=.H.3 uX-Xb [.]XyXaXfXjXc.k ,.7.7.7",
+".7.7.7 +.j.j.j.j.j.j.UX,.=.f.w.E.E.E o.} C *X9 O EX:.P Y.G s.S i., J.Z.B S eXaXu u H.H aXk %.h.KX6 & u [ [ [XyXaXfXjXc.k.u.7.7.7",
+".7.7.7.7 `.j.j v v vXw.I.<X8.( 8 T.c.3 X *.@X% O EX:.P Y.G gX& i.A J.Z.B SX..mXuX; u.f.H 8Xk a.Q.( &X- [ [ [XyXaXfXjXc ,.7.7.7.7",
+".7.7.7.7.7.^ v v v vXw.U > X.3.c.(X1X$X9 L.1 WX0X>X:.P Y.G gX& i.A J.Z.CXOX..mXyXy.t u.f.H aX3 8.N uX- [ [.tXuXa.sXj.k.7.7.7.7.7",
+".7.7.7.7.7 + v v v v `Xw.: >.= XX$.=.< I.D.4 W y EX: . Y.G g @.S.A J.Z.CXOX..mXy.].]X- u.3X6.(.NX8X-X; [.].]XuX.. Xj.u.7.7.7.7.7",
+".7.7.7.7.7.7 ' vXwXw ` `.U.:X,.*.*.*.J $ !.1X< O EX>X: j.& g @.S.A.,.ZX#XO S.mXy.].].t [ u & & uX-X;.t [ [XyXaXfXj.~.7.7.7.7.7.7",
+".7.7.7.7.7.7.7 `.^.^.^ ` `.U.:.: R k.8 $X2.1 WX0 EX>X:.P Y.G sX& i.A J.ZXjXOX..mXy.].].tX- PX-X;X;.t.t [.tXuXa.s ).7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.p :.^.^.^Xw vXq.0X4 / ^ $ !.4.1 O EX>X: . Y.& gX&.S.A.,.ZX#.B SX..mXu.].].t.t.t.t [.] [.tXuXaXf ).=.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.p : ` `Xw _Xq.0X4 /.8 $X2.4.1X< y EX>X: j.&.G UX& i.+ J.Z.CXO SX..mXuXyXyXy.t.tXy.]XyXuXaXf ).=.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.p : ` ` _Xq.0 = /.8 ^X2.4.1 W O yX>X: . Y.& g @.S.A.+ JXzXjXO SX.XaXuXuXyXyXyXuXuXaXaXf ) *.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.p : `XwXq.0X4 k /.J $ !.4.1 O y EX>X: j.&.G UX&.$.$.+XcXzXjXO. SX.XaXaXaXaXaX.Xf.s ).=.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.p :XwXqX7.0 = /.8.FX2 !.1 W O yX>X: . j.&.G UX&.$.$.+.~XcX#XjXOXOXfXfXfXf.s. Xj ).=.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7 +.UXq.0X4 k /.J $ !.4.1X< O EX>X: . Y.& g.bX&.$.$.+.kXcXcX#XjXjXjXjXjXjXj.~.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.p.U.0X4 = /.J.FX2 !.4 W O y E.VX: . Y.&.GXmX&.S.l.#.+.k.~.~XcXcXcXc.k.u.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.U.0 R k h.J.FX2.5.1 W O yX>.V D . Y.&.GXm.bX&.l.l.$.#.#.k.k.k ,.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7 +.: = k.8.J $.D L.1X% O yX>.V D . Y.&.&Xm.b.bX&X&.l.l.l ,.u.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.U k.J.FX2.D L.1X% O EX>.V D . w.&.&.&Xm.b.b N 2.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.:.:.*X2 p L.1X% O y t.V D D . w w.uX9X9.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7",
+".7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.* I p L.1X% O y t t 2 2.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7"
+};
diff --git a/arts/builder/pics/Synth_MULTI_ADD.xpm b/arts/builder/pics/Synth_MULTI_ADD.xpm
new file mode 100644
index 00000000..ec088b69
--- /dev/null
+++ b/arts/builder/pics/Synth_MULTI_ADD.xpm
@@ -0,0 +1,1510 @@
+/* XPM */
+static char * Synth_MULTI_ADD_xpm[] = {
+"64 64 1443 2",
+" c None",
+". c #253073",
+"+ c #273276",
+"@ c #293378",
+"# c #283278",
+"$ c #263077",
+"% c #252F75",
+"& c #232E74",
+"* c #212B71",
+"= c #202A6E",
+"- c #1E296A",
+"; c #1C2667",
+"> c #2B3671",
+", c #313D7B",
+"' c #384288",
+") c #353F87",
+"! c #323D83",
+"~ c #2F3A80",
+"{ c #2D377D",
+"] c #2A357B",
+"^ c #29347A",
+"/ c #273177",
+"( c #253076",
+"_ c #232D72",
+": c #222C72",
+"< c #212C71",
+"[ c #202B70",
+"} c #202A70",
+"| c #1F296E",
+"1 c #1B2463",
+"2 c #3C4988",
+"3 c #434D95",
+"4 c #414C93",
+"5 c #3D488D",
+"6 c #202A6F",
+"7 c #1F2A6F",
+"8 c #1E286C",
+"9 c #37437E",
+"0 c #4F59A0",
+"a c #485399",
+"b c #3B458D",
+"c c #283379",
+"d c #242E74",
+"e c #1E296D",
+"f c #1E286D",
+"g c #1C2669",
+"h c #5862A8",
+"i c #555FA6",
+"j c #3F4B90",
+"k c #1F2A6E",
+"l c #1D276B",
+"m c #1C2668",
+"n c #4B5A97",
+"o c #616CB3",
+"p c #5C67AF",
+"q c #4B579B",
+"r c #2E397F",
+"s c #263177",
+"t c #253075",
+"u c #6872B4",
+"v c #343F84",
+"w c #222C71",
+"x c #212B70",
+"y c #1B2666",
+"z c #1B2366",
+"A c #45538B",
+"B c #445194",
+"C c #2B367B",
+"D c #263076",
+"E c #232E73",
+"F c #1D266B",
+"G c #1E266C",
+"H c #1A2264",
+"I c #1D276A",
+"J c #171F57",
+"K c #4A5996",
+"L c #273277",
+"M c #242F74",
+"N c #1A2664",
+"O c #1E296C",
+"P c #1D296B",
+"Q c #1E2A6C",
+"R c #354186",
+"S c #2C377B",
+"T c #202B6F",
+"U c #6672BC",
+"V c #666EB4",
+"W c #5E6AB4",
+"X c #5A66AC",
+"Y c #565EA4",
+"Z c #525EA4",
+"` c #4E5AA2",
+" . c #4A569C",
+".. c #465296",
+"+. c #424E94",
+"@. c #3E4A8E",
+"#. c #3E468C",
+"$. c #36428C",
+"%. c #363E84",
+"&. c #626EB4",
+"*. c #5E66AC",
+"=. c #5662AB",
+"-. c #525AA4",
+";. c #4E5997",
+">. c #4D578F",
+",. c #4F5789",
+"'. c #4E528A",
+"). c #485381",
+"!. c #444D84",
+"~. c #414984",
+"{. c #3F477B",
+"]. c #3E457B",
+"^. c #3C4376",
+"/. c #3B4174",
+"(. c #383F70",
+"_. c #323A71",
+":. c #31386F",
+"<. c #32396C",
+"[. c #2F376C",
+"}. c #313769",
+"|. c #2F3669",
+"1. c #313868",
+"2. c #2C3469",
+"3. c #2C3368",
+"4. c #2D3566",
+"5. c #2C3267",
+"6. c #2D3465",
+"7. c #2D3464",
+"8. c #2E3263",
+"9. c #2A2F66",
+"0. c #2A3366",
+"a. c #2D3564",
+"b. c #343C60",
+"c. c #333761",
+"d. c #2C3565",
+"e. c #535C94",
+"f. c #676682",
+"g. c #7A7368",
+"h. c #857C5F",
+"i. c #867C58",
+"j. c #817559",
+"k. c #78705D",
+"l. c #766C59",
+"m. c #756B57",
+"n. c #766D52",
+"o. c #766C4D",
+"p. c #776C49",
+"q. c #73694A",
+"r. c #6B634D",
+"s. c #69614D",
+"t. c #6B624B",
+"u. c #6E6549",
+"v. c #716647",
+"w. c #736845",
+"x. c #716546",
+"y. c #68614A",
+"z. c #675F4B",
+"A. c #696149",
+"B. c #6E6347",
+"C. c #6F6545",
+"D. c #726843",
+"E. c #686048",
+"F. c #665F49",
+"G. c #6A6247",
+"H. c #796F3F",
+"I. c #85793A",
+"J. c #82793B",
+"K. c #615F4B",
+"L. c #363D60",
+"M. c #1E286A",
+"N. c #1D2769",
+"O. c #6A687F",
+"P. c #9F8E4A",
+"Q. c #CBAB28",
+"R. c #D6B21D",
+"S. c #DCB719",
+"T. c #D6B31C",
+"U. c #CDAC22",
+"V. c #C8A821",
+"W. c #CCAB1E",
+"X. c #CFAD1B",
+"Y. c #CEAC1A",
+"Z. c #D5B115",
+"`. c #D1AE17",
+" + c #C8A71C",
+".+ c #C4A41D",
+"++ c #CAA91B",
+"@+ c #CDAA18",
+"#+ c #CDAB19",
+"$+ c #D0AD17",
+"%+ c #D1AE18",
+"&+ c #C4A51B",
+"*+ c #D8B513",
+"=+ c #E3BF0E",
+"-+ c #E5C10C",
+";+ c #BBA423",
+">+ c #636151",
+",+ c #2F3568",
+"'+ c #222E74",
+")+ c #1E2868",
+"!+ c #1A235E",
+"~+ c #5A62AC",
+"{+ c #565A91",
+"]+ c #847B69",
+"^+ c #D1B023",
+"/+ c #F7CA05",
+"(+ c #FBCD02",
+"_+ c #F6C905",
+":+ c #EFC409",
+"<+ c #F1C607",
+"[+ c #F5C905",
+"}+ c #F1C507",
+"|+ c #FACC02",
+"1+ c #F4C805",
+"2+ c #EEC308",
+"3+ c #F5C804",
+"4+ c #F2C606",
+"5+ c #F8CB03",
+"6+ c #FACD02",
+"7+ c #FECF00",
+"8+ c #E5C10D",
+"9+ c #7F753F",
+"0+ c #353D69",
+"a+ c #222A6F",
+"b+ c #212B6C",
+"c+ c #20296C",
+"d+ c #4E569C",
+"e+ c #525987",
+"f+ c #8A7F5B",
+"g+ c #DFB918",
+"h+ c #FACC03",
+"i+ c #F8CB04",
+"j+ c #E2BB11",
+"k+ c #DDB713",
+"l+ c #E0B910",
+"m+ c #E3BB0E",
+"n+ c #E1B910",
+"o+ c #E9C00B",
+"p+ c #E5BD0D",
+"q+ c #DCB612",
+"r+ c #DBB612",
+"s+ c #E0B90F",
+"t+ c #E9C00A",
+"u+ c #E5BC0D",
+"v+ c #DBB512",
+"w+ c #DCB712",
+"x+ c #E2BB0E",
+"y+ c #EAC10A",
+"z+ c #F1C807",
+"A+ c #F5CC04",
+"B+ c #D1B517",
+"C+ c #716C45",
+"D+ c #34405B",
+"E+ c #262E73",
+"F+ c #222E6C",
+"G+ c #222D6E",
+"H+ c #4E5AA4",
+"I+ c #4A5A9C",
+"J+ c #4A529C",
+"K+ c #4D558B",
+"L+ c #7E7564",
+"M+ c #CEAE22",
+"N+ c #F6CA06",
+"O+ c #F2C608",
+"P+ c #DCB714",
+"Q+ c #B99C29",
+"R+ c #9D8936",
+"S+ c #92813A",
+"T+ c #958238",
+"U+ c #968238",
+"V+ c #9C8634",
+"W+ c #988435",
+"X+ c #917F38",
+"Y+ c #8D7C3B",
+"Z+ c #917F39",
+"`+ c #958236",
+" @ c #968335",
+".@ c #9C8733",
+"+@ c #998537",
+"@@ c #928037",
+"#@ c #8E7D3B",
+"$@ c #92803B",
+"%@ c #968239",
+"&@ c #978437",
+"*@ c #9D8833",
+"=@ c #998639",
+"-@ c #927E39",
+";@ c #8F7E3B",
+">@ c #948238",
+",@ c #A4902F",
+"'@ c #AF9A29",
+")@ c #B09C29",
+"!@ c #867B40",
+"~@ c #4D5165",
+"{@ c #293071",
+"]@ c #263273",
+"^@ c #252D72",
+"/@ c #253071",
+"(@ c #242F6E",
+"_@ c #232E6E",
+":@ c #46529C",
+"<@ c #425294",
+"[@ c #424A94",
+"}@ c #424D8A",
+"|@ c #605E73",
+"1@ c #9C8945",
+"2@ c #D2B01F",
+"3@ c #EDC30B",
+"4@ c #F2C707",
+"5@ c #E4BC0F",
+"6@ c #BB9E27",
+"7@ c #857643",
+"8@ c #5F5A56",
+"9@ c #474963",
+"0@ c #484863",
+"a@ c #464860",
+"b@ c #474860",
+"c@ c #434564",
+"d@ c #42455F",
+"e@ c #454661",
+"f@ c #474761",
+"g@ c #484B5F",
+"h@ c #47495C",
+"i@ c #494A60",
+"j@ c #444767",
+"k@ c #43485D",
+"l@ c #484A61",
+"m@ c #474966",
+"n@ c #484B68",
+"o@ c #484A60",
+"p@ c #4C4E61",
+"q@ c #43476A",
+"r@ c #474D5B",
+"s@ c #4A4D67",
+"t@ c #565759",
+"u@ c #525855",
+"v@ c #464964",
+"w@ c #2B3A69",
+"x@ c #263171",
+"y@ c #232E6C",
+"z@ c #212B69",
+"A@ c #464E94",
+"B@ c #3A468C",
+"C@ c #444984",
+"D@ c #63626C",
+"E@ c #958345",
+"F@ c #CAAA20",
+"G@ c #ECC20A",
+"H@ c #F0C508",
+"I@ c #BDA022",
+"J@ c #7A6F46",
+"K@ c #494963",
+"L@ c #2C366F",
+"M@ c #28326E",
+"N@ c #2B3472",
+"O@ c #273173",
+"P@ c #283272",
+"Q@ c #2B3572",
+"R@ c #2B3471",
+"S@ c #2B3773",
+"T@ c #2C3775",
+"U@ c #2C3574",
+"V@ c #2B3673",
+"W@ c #2D3877",
+"X@ c #2B3578",
+"Y@ c #2B3672",
+"Z@ c #2E3977",
+"`@ c #2E397B",
+" # c #2C3772",
+".# c #2C377A",
+"+# c #2D347A",
+"@# c #2F3971",
+"## c #2E3579",
+"$# c #2D387A",
+"%# c #2A3274",
+"&# c #2A327C",
+"*# c #26366C",
+"=# c #293474",
+"-# c #273273",
+";# c #273271",
+"># c #3E4A94",
+",# c #3A428C",
+"'# c #3E467C",
+")# c #5A576A",
+"!# c #8E7F44",
+"~# c #C3A521",
+"{# c #E9C00C",
+"]# c #FFD000",
+"^# c #BC9F23",
+"/# c #7B7048",
+"(# c #4A4C5E",
+"_# c #303A6A",
+":# c #293475",
+"<# c #2A357A",
+"[# c #2A3675",
+"}# c #2A3674",
+"|# c #2C3878",
+"1# c #2D3978",
+"2# c #2D3777",
+"3# c #2D3976",
+"4# c #2D3775",
+"5# c #2B3873",
+"6# c #2F3B77",
+"7# c #30397E",
+"8# c #2F3775",
+"9# c #2A386E",
+"0# c #2A367C",
+"a# c #2E3A7D",
+"b# c #293579",
+"c# c #293574",
+"d# c #293575",
+"e# c #293473",
+"f# c #263170",
+"g# c #323E84",
+"h# c #3A447E",
+"i# c #4E5064",
+"j# c #807349",
+"k# c #C0A123",
+"l# c #EAC10B",
+"m# c #F6C904",
+"n# c #E5BD0E",
+"o# c #BC9E25",
+"p# c #847643",
+"q# c #515160",
+"r# c #333B72",
+"s# c #2C3779",
+"t# c #2B3679",
+"u# c #2B3877",
+"v# c #2E397C",
+"w# c #2D397C",
+"x# c #2D397A",
+"y# c #2E3B7A",
+"z# c #2E387D",
+"A# c #2F3B7D",
+"B# c #2E3C7A",
+"C# c #2F387D",
+"D# c #2F3B7F",
+"E# c #313D7F",
+"F# c #303E7E",
+"G# c #2F387C",
+"H# c #2E367C",
+"I# c #2C3877",
+"J# c #2C3777",
+"K# c #2A3676",
+"L# c #2B3571",
+"M# c #323A84",
+"N# c #2E3676",
+"O# c #484C67",
+"P# c #7A6F49",
+"Q# c #BD9F23",
+"R# c #EEC309",
+"S# c #C8A81E",
+"T# c #90803E",
+"U# c #565661",
+"V# c #323D77",
+"W# c #2E387B",
+"X# c #2E3A7C",
+"Y# c #2E3B7B",
+"Z# c #2F3C7C",
+"`# c #2F3D7C",
+" $ c #303D7D",
+".$ c #303D7E",
+"+$ c #313F7E",
+"@$ c #313E80",
+"#$ c #313D7D",
+"$$ c #313E7F",
+"%$ c #324081",
+"&$ c #323E81",
+"*$ c #2E3E7C",
+"=$ c #2D3A79",
+"-$ c #283677",
+";$ c #283378",
+">$ c #494B69",
+",$ c #796F46",
+"'$ c #B89C27",
+")$ c #E3BB0F",
+"!$ c #CBAA1D",
+"~$ c #8B7D43",
+"{$ c #525363",
+"]$ c #353F79",
+"^$ c #2F3C7D",
+"/$ c #2F3C7E",
+"($ c #303C7D",
+"_$ c #313E7E",
+":$ c #323E7E",
+"<$ c #333F7F",
+"[$ c #323F7E",
+"}$ c #333F80",
+"|$ c #344081",
+"1$ c #333F7E",
+"2$ c #33417F",
+"3$ c #354183",
+"4$ c #34407E",
+"5$ c #2F3B7E",
+"6$ c #303980",
+"7$ c #2F3C7A",
+"8$ c #2A347C",
+"9$ c #2A3279",
+"0$ c #2F3676",
+"a$ c #484B66",
+"b$ c #7B6F4B",
+"c$ c #B59A29",
+"d$ c #DFB912",
+"e$ c #EDC30A",
+"f$ c #C8A820",
+"g$ c #8C7E43",
+"h$ c #5B5C64",
+"i$ c #3B4578",
+"j$ c #313E7D",
+"k$ c #313F81",
+"l$ c #334082",
+"m$ c #334080",
+"n$ c #344183",
+"o$ c #354284",
+"p$ c #35417E",
+"q$ c #344284",
+"r$ c #364386",
+"s$ c #364385",
+"t$ c #364282",
+"u$ c #354383",
+"v$ c #344180",
+"w$ c #2B3776",
+"x$ c #2B3675",
+"y$ c #283370",
+"z$ c #29337C",
+"A$ c #273375",
+"B$ c #293477",
+"C$ c #2E3870",
+"D$ c #454969",
+"E$ c #746B51",
+"F$ c #AE962C",
+"G$ c #E2BB10",
+"H$ c #EBC20B",
+"I$ c #D1AF1B",
+"J$ c #9C8A3D",
+"K$ c #636160",
+"L$ c #414976",
+"M$ c #344181",
+"N$ c #344281",
+"O$ c #354280",
+"P$ c #344282",
+"Q$ c #34427F",
+"R$ c #374280",
+"S$ c #364482",
+"T$ c #374487",
+"U$ c #374582",
+"V$ c #374586",
+"W$ c #384485",
+"X$ c #344080",
+"Y$ c #2D3876",
+"Z$ c #26327B",
+"`$ c #273477",
+" % c #2A3475",
+".% c #2B357A",
+"+% c #2E3A72",
+"@% c #43496B",
+"#% c #706951",
+"$% c #B2992D",
+"%% c #E0B912",
+"&% c #D7B418",
+"*% c #9E8B3D",
+"=% c #636161",
+"-% c #404A77",
+";% c #354283",
+">% c #364283",
+",% c #364382",
+"'% c #374385",
+")% c #384584",
+"!% c #354482",
+"~% c #384588",
+"{% c #384587",
+"]% c #394585",
+"^% c #394587",
+"/% c #394686",
+"(% c #394687",
+"_% c #374483",
+":% c #354382",
+"<% c #354282",
+"[% c #2B3775",
+"}% c #26327C",
+"|% c #2A337C",
+"1% c #283570",
+"2% c #2B377D",
+"3% c #2D377C",
+"4% c #2B3678",
+"5% c #43496E",
+"6% c #706B57",
+"7% c #AA9333",
+"8% c #DDB814",
+"9% c #F3C807",
+"0% c #F0C509",
+"a% c #D1B01C",
+"b% c #9E8D3D",
+"c% c #666561",
+"d% c #444D7A",
+"e% c #374681",
+"f% c #374482",
+"g% c #384585",
+"h% c #374684",
+"i% c #374685",
+"j% c #374480",
+"k% c #3A4686",
+"l% c #394885",
+"m% c #3A4988",
+"n% c #3A4A8A",
+"o% c #3A4989",
+"p% c #3A4786",
+"q% c #2F3B78",
+"r% c #2B3674",
+"s% c #263176",
+"t% c #283473",
+"u% c #2C387D",
+"v% c #2A3778",
+"w% c #2E3B7C",
+"x% c #444A73",
+"y% c #6A665B",
+"z% c #AB9433",
+"A% c #DBB716",
+"B% c #EFC40A",
+"C% c #D5B21B",
+"D% c #9E8D3F",
+"E% c #616266",
+"F% c #414B7E",
+"G% c #374682",
+"H% c #3A4785",
+"I% c #394884",
+"J% c #394888",
+"K% c #3C4886",
+"L% c #3C4A8B",
+"M% c #3C4A87",
+"N% c #3A4887",
+"O% c #394685",
+"P% c #384685",
+"Q% c #384583",
+"R% c #2A337B",
+"S% c #2E3976",
+"T% c #333D79",
+"U% c #313D77",
+"V% c #333E7A",
+"W% c #484F74",
+"X% c #6E6A5B",
+"Y% c #A99337",
+"Z% c #DCB815",
+"`% c #F3C707",
+" & c #F1C608",
+".& c #CEAE20",
+"+& c #7E7754",
+"@& c #485077",
+"#& c #3B4987",
+"$& c #364582",
+"%& c #384682",
+"&& c #3C498A",
+"*& c #3C4B85",
+"=& c #3B4A87",
+"-& c #3D4C8C",
+";& c #3E4B8C",
+">& c #3D4B8C",
+",& c #3B4988",
+"'& c #394786",
+")& c #33407D",
+"!& c #263174",
+"~& c #27347B",
+"{& c #2D3A7F",
+"]& c #2F3A7B",
+"^& c #364280",
+"/& c #4B5173",
+"(& c #807752",
+"_& c #BFA428",
+":& c #E6BE10",
+"<& c #F2C708",
+"[& c #D7B41A",
+"}& c #897E51",
+"|& c #4D557A",
+"1& c #3B4983",
+"2& c #384883",
+"3& c #3D4A88",
+"4& c #3D4C8A",
+"5& c #3C4B88",
+"6& c #394986",
+"7& c #3C4A84",
+"8& c #3F4C8C",
+"9& c #3F4E8E",
+"0& c #3E4E8A",
+"a& c #3E4E8D",
+"b& c #3E4D8B",
+"c& c #3D4B8A",
+"d& c #3A4888",
+"e& c #3A4787",
+"f& c #242E73",
+"g& c #263279",
+"h& c #283276",
+"i& c #283478",
+"j& c #2A3771",
+"k& c #303C7F",
+"l& c #33407F",
+"m& c #384681",
+"n& c #54576E",
+"o& c #8B7E4A",
+"p& c #C7A925",
+"q& c #E9C00E",
+"r& c #F0C609",
+"s& c #CDAD21",
+"t& c #7E7658",
+"u& c #4B5380",
+"v& c #394783",
+"w& c #3B488A",
+"x& c #3B498A",
+"y& c #3B4B88",
+"z& c #3F4D89",
+"A& c #3E4D88",
+"B& c #3F4F89",
+"C& c #414E91",
+"D& c #404F8E",
+"E& c #404E8D",
+"F& c #404D8C",
+"G& c #3E4C8B",
+"H& c #3C4A89",
+"I& c #3A4886",
+"J& c #35427E",
+"K& c #262F73",
+"L& c #283277",
+"M& c #27327C",
+"N& c #2B3579",
+"O& c #2C387B",
+"P& c #37437F",
+"Q& c #54566E",
+"R& c #807451",
+"S& c #BCA029",
+"T& c #BBA12E",
+"U& c #6D6B64",
+"V& c #455085",
+"W& c #3B4986",
+"X& c #3E4B8A",
+"Y& c #3C4B89",
+"Z& c #3F4C88",
+"`& c #404F8D",
+" * c #41518D",
+".* c #42518C",
+"+* c #42508F",
+"@* c #41518E",
+"#* c #404F90",
+"$* c #3F4E8C",
+"%* c #323F7C",
+"&* c #243073",
+"** c #26346F",
+"=* c #2B3779",
+"-* c #2F3B79",
+";* c #354078",
+">* c #55586D",
+",* c #867A4E",
+"'* c #BFA229",
+")* c #E6BE0F",
+"!* c #EEC40B",
+"~* c #E7BF0F",
+"{* c #C9AA23",
+"]* c #8D814B",
+"^* c #575C78",
+"/* c #3F4B85",
+"(* c #3E4C88",
+"_* c #3F4E8B",
+":* c #41508E",
+"<* c #425190",
+"[* c #414E8A",
+"}* c #43538D",
+"|* c #42528E",
+"1* c #435190",
+"2* c #41508C",
+"3* c #404E8C",
+"4* c #3E4D8C",
+"5* c #232D71",
+"6* c #242E71",
+"7* c #283077",
+"8* c #28327C",
+"9* c #283477",
+"0* c #28347C",
+"a* c #2A3678",
+"b* c #3B4478",
+"c* c #5B5B65",
+"d* c #8C7D49",
+"e* c #C6A821",
+"f* c #E9C00D",
+"g* c #F5C906",
+"h* c #E5BE10",
+"i* c #BFA329",
+"j* c #8D824E",
+"k* c #5F6170",
+"l* c #444E85",
+"m* c #3F4D8E",
+"n* c #3E4C8D",
+"o* c #3E4D8A",
+"p* c #414E90",
+"q* c #425090",
+"r* c #425290",
+"s* c #44548E",
+"t* c #44538E",
+"u* c #455294",
+"v* c #43528E",
+"w* c #445295",
+"x* c #435391",
+"y* c #42518F",
+"z* c #3F4D8A",
+"A* c #3E4B89",
+"B* c #3B4885",
+"C* c #212A6F",
+"D* c #212D72",
+"E* c #2A3477",
+"F* c #364068",
+"G* c #5F5F62",
+"H* c #958441",
+"I* c #CBAA20",
+"J* c #BDA22A",
+"K* c #837851",
+"L* c #595D72",
+"M* c #424F83",
+"N* c #3C4A88",
+"O* c #3F4D8C",
+"P* c #42508D",
+"Q* c #41508D",
+"R* c #43528C",
+"S* c #43548F",
+"T* c #445494",
+"U* c #44548C",
+"V* c #445293",
+"W* c #445391",
+"X* c #435090",
+"Y* c #42518E",
+"Z* c #3A4885",
+"`* c #374581",
+" = c #232C71",
+".= c #242F76",
+"+= c #252F73",
+"@= c #253176",
+"#= c #2D3970",
+"$= c #3E456C",
+"%= c #65635A",
+"&= c #9B893D",
+"*= c #CEAD1C",
+"== c #EEC30A",
+"-= c #E3BC11",
+";= c #B89E2D",
+">= c #7E7756",
+",= c #535972",
+"'= c #3F4A88",
+")= c #3C4B8C",
+"!= c #3E4E8E",
+"~= c #414F8C",
+"{= c #455391",
+"]= c #475694",
+"^= c #445493",
+"/= c #455394",
+"(= c #424F8C",
+"_= c #465494",
+":= c #46588F",
+"<= c #45568F",
+"[= c #455491",
+"}= c #445390",
+"|= c #35417C",
+"1= c #212D71",
+"2= c #222D71",
+"3= c #253173",
+"4= c #2E3575",
+"5= c #424866",
+"6= c #71694F",
+"7= c #A79133",
+"8= c #D6B218",
+"9= c #DBB616",
+"0= c #AD9634",
+"a= c #756F5A",
+"b= c #4E5379",
+"c= c #3B4889",
+"d= c #3A4684",
+"e= c #3B4B8C",
+"f= c #404E90",
+"g= c #435290",
+"h= c #42538D",
+"i= c #455494",
+"j= c #455593",
+"k= c #44558D",
+"l= c #465690",
+"m= c #475793",
+"n= c #485495",
+"o= c #475594",
+"p= c #465592",
+"q= c #202C71",
+"r= c #222B70",
+"s= c #222E72",
+"t= c #2B3570",
+"u= c #474961",
+"v= c #786E4B",
+"w= c #B59A28",
+"x= c #D9B517",
+"y= c #A79138",
+"z= c #6E6C5D",
+"A= c #495176",
+"B= c #384687",
+"C= c #3B478C",
+"D= c #3A4A8C",
+"E= c #3D498D",
+"F= c #3E4E8C",
+"G= c #435191",
+"H= c #465491",
+"I= c #485795",
+"J= c #475496",
+"K= c #485894",
+"L= c #46568B",
+"M= c #495A92",
+"N= c #495996",
+"O= c #495992",
+"P= c #414F8A",
+"Q= c #1F2B6E",
+"R= c #222C70",
+"S= c #232E72",
+"T= c #262F72",
+"U= c #464966",
+"V= c #7A6E46",
+"W= c #B99D26",
+"X= c #E3BC0F",
+"Y= c #F0C507",
+"Z= c #D5B218",
+"`= c #A49038",
+" - c #6C6A5F",
+".- c #474E7B",
+"+- c #384481",
+"@- c #3E4B8D",
+"#- c #424F8F",
+"$- c #425292",
+"%- c #435291",
+"&- c #45528D",
+"*- c #465594",
+"=- c #43548C",
+"-- c #475991",
+";- c #4A5A99",
+">- c #485791",
+",- c #485593",
+"'- c #4B5B9A",
+")- c #4C5B98",
+"!- c #4A5A95",
+"~- c #495894",
+"{- c #404E8A",
+"]- c #3E4D89",
+"^- c #394680",
+"/- c #1F2A6D",
+"(- c #1F286D",
+"_- c #26306E",
+":- c #424460",
+"<- c #786C45",
+"[- c #BC9F22",
+"}- c #E7BF0C",
+"|- c #C9A91E",
+"1- c #9A873B",
+"2- c #646362",
+"3- c #454B77",
+"4- c #384581",
+"5- c #384688",
+"6- c #384888",
+"7- c #3B498C",
+"8- c #42508E",
+"9- c #435292",
+"0- c #455492",
+"a- c #465695",
+"b- c #475691",
+"c- c #48568F",
+"d- c #47578F",
+"e- c #495993",
+"f- c #48568C",
+"g- c #4C5C9C",
+"h- c #4C5D9C",
+"i- c #4D5E98",
+"j- c #333E78",
+"k- c #1E296E",
+"l- c #1E2A6D",
+"m- c #2A3168",
+"n- c #494A5C",
+"o- c #7C6F42",
+"p- c #BEA021",
+"q- c #EBC10A",
+"r- c #F5C904",
+"s- c #BB9F25",
+"t- c #867940",
+"u- c #585862",
+"v- c #3E4877",
+"w- c #344483",
+"x- c #384285",
+"y- c #384684",
+"z- c #3A4687",
+"A- c #3E4A84",
+"B- c #414E92",
+"C- c #405090",
+"D- c #44528F",
+"E- c #45558F",
+"F- c #4A5898",
+"G- c #485A92",
+"H- c #4A599C",
+"I- c #4A5891",
+"J- c #4B5A95",
+"K- c #4B5B96",
+"L- c #4D5D97",
+"M- c #4E5F98",
+"N- c #505E99",
+"O- c #4F5E9D",
+"P- c #4C5D98",
+"Q- c #485893",
+"R- c #455390",
+"S- c #2E3566",
+"T- c #535054",
+"U- c #8E7C38",
+"V- c #C5A51D",
+"W- c #BDA023",
+"X- c #7C7146",
+"Y- c #4D4F63",
+"Z- c #363E74",
+"`- c #2F3B7C",
+" ; c #344280",
+".; c #364483",
+"+; c #3A478C",
+"@; c #3B4A8D",
+"#; c #414E8C",
+"$; c #445291",
+"%; c #465593",
+"&; c #46568E",
+"*; c #485A91",
+"=; c #485897",
+"-; c #4A578D",
+";; c #4B5C95",
+">; c #4B5A93",
+",; c #4E5E99",
+"'; c #4E5E97",
+"); c #4D5D98",
+"!; c #4F5F9C",
+"~; c #4C5C97",
+"{; c #475692",
+"]; c #3A4883",
+"^; c #1E276C",
+"/; c #2A3266",
+"(; c #545052",
+"_; c #968333",
+":; c #D5B114",
+"<; c #F3C705",
+"[; c #C5A51E",
+"}; c #87793D",
+"|; c #585759",
+"1; c #40466F",
+"2; c #3E466F",
+"3; c #434B72",
+"4; c #474E7A",
+"5; c #495077",
+"6; c #4A527B",
+"7; c #4A537F",
+"8; c #4D567E",
+"9; c #4D567F",
+"0; c #4D577F",
+"a; c #4C5782",
+"b; c #4D5785",
+"c; c #4D5788",
+"d; c #4E5889",
+"e; c #525E8A",
+"f; c #525E87",
+"g; c #535E8C",
+"h; c #56608B",
+"i; c #53608C",
+"j; c #536090",
+"k; c #535F8B",
+"l; c #556396",
+"m; c #526296",
+"n; c #52639D",
+"o; c #4D5E9C",
+"p; c #4A5991",
+"q; c #4F5A94",
+"r; c #1D286C",
+"s; c #1D276C",
+"t; c #232A69",
+"u; c #434459",
+"v; c #8E7D36",
+"w; c #D3B015",
+"x; c #D8B314",
+"y; c #BA9D24",
+"z; c #988535",
+"A; c #807445",
+"B; c #7E734A",
+"C; c #817545",
+"D; c #887B43",
+"E; c #8A7C48",
+"F; c #8B7F4D",
+"G; c #897E4F",
+"H; c #867C53",
+"I; c #867D54",
+"J; c #8C8151",
+"K; c #8E8351",
+"L; c #8D8152",
+"M; c #867E57",
+"N; c #817B5C",
+"O; c #7E7960",
+"P; c #807A62",
+"Q; c #837E60",
+"R; c #89835C",
+"S; c #8C8460",
+"T; c #8A835A",
+"U; c #878063",
+"V; c #817B64",
+"W; c #7B796A",
+"X; c #7B7B70",
+"Y; c #777771",
+"Z; c #687086",
+"`; c #5A6894",
+" > c #52629B",
+".> c #4B5A8D",
+"+> c #4A5A9A",
+"@> c #4E5E94",
+"#> c #4A5994",
+"$> c #495693",
+"%> c #455490",
+"&> c #1C276A",
+"*> c #282F66",
+"=> c #5A554E",
+"-> c #BE9F1F",
+";> c #F8CB02",
+">> c #EDC209",
+",> c #E7BF0B",
+"'> c #DEB812",
+")> c #D6B316",
+"!> c #D6B217",
+"~> c #DCB713",
+"{> c #E0BA11",
+"]> c #E0BA12",
+"^> c #DEB915",
+"/> c #D9B619",
+"(> c #D9B61A",
+"_> c #DFBA16",
+":> c #E2BC14",
+"<> c #DCB818",
+"[> c #D9B61B",
+"}> c #D3B220",
+"|> c #CEAF24",
+"1> c #CEAF25",
+"2> c #D3B321",
+"3> c #D8B61E",
+"4> c #D9B71E",
+"5> c #D3B323",
+"6> c #CBAD2A",
+"7> c #C2A834",
+"8> c #C1A834",
+"9> c #B9A33C",
+"0> c #9B9055",
+"a> c #70757C",
+"b> c #535E87",
+"c> c #4F6097",
+"d> c #4B5C97",
+"e> c #4A5A9B",
+"f> c #4A5A94",
+"g> c #3E4B85",
+"h> c #282F65",
+"i> c #59544F",
+"j> c #BA9C1F",
+"k> c #F2C605",
+"l> c #F7CA03",
+"m> c #F4C806",
+"n> c #F6CA04",
+"o> c #F7CA04",
+"p> c #F4C906",
+"q> c #F6CA05",
+"r> c #F3C808",
+"s> c #F0C60A",
+"t> c #F0C60B",
+"u> c #F4C808",
+"v> c #F7CB05",
+"w> c #F5C907",
+"x> c #F4C908",
+"y> c #F0C60C",
+"z> c #ECC30F",
+"A> c #ECC40F",
+"B> c #ECC410",
+"C> c #CCAF2C",
+"D> c #88815F",
+"E> c #5D678B",
+"F> c #50609A",
+"G> c #4B5A92",
+"H> c #212A66",
+"I> c #40415B",
+"J> c #7F703D",
+"K> c #B89A22",
+"L> c #CDAB18",
+"M> c #D2AF15",
+"N> c #D3B016",
+"O> c #D5B116",
+"P> c #D7B316",
+"Q> c #D6B216",
+"R> c #DDB815",
+"S> c #E3BD13",
+"T> c #E4BD12",
+"U> c #E8C010",
+"V> c #E4BE12",
+"W> c #E0BB16",
+"X> c #E0BA17",
+"Y> c #E5BE13",
+"Z> c #E9C110",
+"`> c #E8C012",
+" , c #E9C111",
+"., c #E6BF13",
+"+, c #E4BE15",
+"@, c #E8C111",
+"#, c #CCAE28",
+"$, c #888367",
+"%, c #5C6789",
+"&, c #4A5888",
+"*, c #4A5A8D",
+"=, c #465694",
+"-, c #46528C",
+";, c #1D266A",
+">, c #232C62",
+",, c #3E4058",
+"', c #59544E",
+"), c #6B6348",
+"!, c #746944",
+"~, c #776C48",
+"{, c #7A6F47",
+"], c #796F47",
+"^, c #7A7046",
+"/, c #7D724A",
+"(, c #83774A",
+"_, c #887B45",
+":, c #897C47",
+"<, c #8A7D48",
+"[, c #867B4C",
+"}, c #857B51",
+"|, c #8D8250",
+"1, c #95884B",
+"2, c #9A8B46",
+"3, c #A18F42",
+"4, c #9F8F45",
+"5, c #9C8D48",
+"6, c #9D8E49",
+"7, c #A29246",
+"8, c #A79543",
+"9, c #A89744",
+"0, c #A99744",
+"a, c #A69645",
+"b, c #AA9846",
+"c, c #B49F3E",
+"d, c #BDA536",
+"e, c #B8A13A",
+"f, c #9A8F56",
+"g, c #6E727C",
+"h, c #515B84",
+"i, c #4C5C94",
+"j, c #45548F",
+"k, c #222B68",
+"l, c #273068",
+"m, c #2C3361",
+"n, c #2E3565",
+"o, c #343B69",
+"p, c #383E68",
+"q, c #373F66",
+"r, c #38406D",
+"s, c #3B426F",
+"t, c #3F4670",
+"u, c #404870",
+"v, c #444B71",
+"w, c #434B76",
+"x, c #454D75",
+"y, c #46507B",
+"z, c #48527D",
+"A, c #4C557D",
+"B, c #50587D",
+"C, c #555B74",
+"D, c #575C75",
+"E, c #5C6074",
+"F, c #5A5E78",
+"G, c #5A607A",
+"H, c #5E637B",
+"I, c #606577",
+"J, c #636875",
+"K, c #616677",
+"L, c #646978",
+"M, c #676B76",
+"N, c #6F6F6B",
+"O, c #76756F",
+"P, c #747475",
+"Q, c #656C81",
+"R, c #535C83",
+"S, c #4D5A94",
+"T, c #1B2667",
+"U, c #1C2768",
+"V, c #1B2767",
+"W, c #1B2665",
+"X, c #1F2B6D",
+"Y, c #222D6F",
+"Z, c #232F6E",
+"`, c #253072",
+" ' c #273373",
+".' c #2D3979",
+"+' c #2D3977",
+"@' c #2E3A7B",
+"#' c #323F7F",
+"$' c #354281",
+"%' c #3C4C85",
+"&' c #3D4B88",
+"*' c #404D85",
+"=' c #414F89",
+"-' c #424F89",
+";' c #445289",
+">' c #45528F",
+",' c #46538E",
+"'' c #475591",
+")' c #495592",
+"!' c #4A588E",
+"~' c #4C5A90",
+"{' c #4F5C8C",
+"]' c #4F5B8B",
+"^' c #4B5788",
+"/' c #4A5894",
+"(' c #4A5992",
+"_' c #485794",
+":' c #4A5694",
+"<' c #1E266B",
+"[' c #1D2668",
+"}' c #1E2869",
+"|' c #1C2867",
+"1' c #1E2A69",
+"2' c #222E6D",
+"3' c #263173",
+"4' c #2D3A77",
+"5' c #2E3A7A",
+"6' c #323E7F",
+"7' c #394684",
+"8' c #3A4A84",
+"9' c #3E4A8C",
+"0' c #3D4987",
+"a' c #3D4C8B",
+"b' c #40508C",
+"c' c #44538F",
+"d' c #485592",
+"e' c #485792",
+"f' c #485895",
+"g' c #46568C",
+"h' c #42528C",
+"i' c #1A2665",
+"j' c #1E276B",
+"k' c #1F296C",
+"l' c #222C6F",
+"m' c #263271",
+"n' c #2A3574",
+"o' c #2A3576",
+"p' c #364684",
+"q' c #3C4884",
+"r' c #3D4A87",
+"s' c #3D4A89",
+"t' c #42508C",
+"u' c #44528B",
+"v' c #46548E",
+"w' c #465493",
+"x' c #475593",
+"y' c #475490",
+"z' c #4A5794",
+"A' c #424E8C",
+"B' c #3C477A",
+"C' c #1A2467",
+"D' c #1C2769",
+"E' c #1D2969",
+"F' c #1C2868",
+"G' c #202C6C",
+"H' c #232F6F",
+"I' c #243074",
+"J' c #243075",
+"K' c #2A3677",
+"L' c #2F3A7E",
+"M' c #333F7C",
+"N' c #354182",
+"O' c #3B4A88",
+"P' c #3F4D88",
+"Q' c #404F8C",
+"R' c #44518C",
+"S' c #445490",
+"T' c #445492",
+"U' c #43538F",
+"V' c #445491",
+"W' c #485693",
+"X' c #465284",
+"Y' c #1B2464",
+"Z' c #1C266A",
+"`' c #1E276D",
+" ) c #202A6C",
+".) c #1F2B6A",
+"+) c #25316F",
+"@) c #2C367D",
+"#) c #2E3A74",
+"$) c #2F3B7A",
+"%) c #303F7C",
+"&) c #324283",
+"*) c #404E8B",
+"=) c #404F8A",
+"-) c #43528F",
+";) c #44528E",
+">) c #475794",
+",) c #465294",
+"') c #3A4475",
+")) c #182059",
+"!) c #1A2462",
+"~) c #1D2869",
+"{) c #1F296A",
+"]) c #212A6D",
+"^) c #252F6F",
+"/) c #263272",
+"() c #283275",
+"_) c #2E3A77",
+":) c #3B4887",
+"<) c #3E4C89",
+"[) c #40508D",
+"}) c #42528F",
+"|) c #43538C",
+"1) c #45558C",
+"2) c #1B2565",
+"3) c #202B6B",
+"4) c #25306F",
+"5) c #263172",
+"6) c #283373",
+"7) c #2B3777",
+"8) c #2D3A78",
+"9) c #303C7B",
+"0) c #3C4987",
+"a) c #3E4B88",
+"b) c #3E4C8A",
+"c) c #3E4E89",
+"d) c #3F4E8A",
+"e) c #414E89",
+"f) c #42518D",
+"g) c #414F8B",
+"h) c #445190",
+"i) c #42528D",
+"j) c #42518B",
+"k) c #3C467F",
+"l) c #1C2664",
+"m) c #1F2A6B",
+"n) c #242F6F",
+"o) c #3F4F8A",
+"p) c #40508B",
+"q) c #1D2765",
+"r) c #2A3575",
+"s) c #3C4A86",
+"t) c #3C4B87",
+"u) c #404F8B",
+"v) c #3D4B87",
+"w) c #3D4C88",
+"x) c #3F4C87",
+" . + @ @ # $ % & * = - ; ",
+" > , ' ) ! ~ { ] ^ / ( % _ : < [ } | 1 1 ",
+" 2 3 4 5 ' ) ! ~ { ] ^ / ( % _ : < [ 6 7 | | 8 1 ",
+" 9 0 0 a 3 4 b ' ) ! ~ { ] c / ( d _ : < [ 6 7 | e f f 8 g 1 ",
+" h h i 0 a 3 j b ' ) ! ~ { ] c / ( d _ : * [ 6 k | e f 8 8 8 l m ",
+" n o p i 0 q a 3 j b ' ) ! r { ] c s t d _ : * [ 6 | | e f 8 8 l l l g 1 ",
+" u o p h i 0 q a 4 5 b ' v ! r { ] # s % d _ w x } 6 | | e f 8 8 l l y z m m ",
+" A u u o p h i 0 a B 4 5 b ' ! ~ r C ^ # D % E _ < x 6 7 | | f 8 8 8 l F G G H I m J ",
+" K u u o o p i 0 q a 3 j b ' ) ! ~ { ] ^ L D M E _ < x 6 k | e f 8 8 l y G G N G H g m J ",
+" n u u u o p h i 0 q a 3 j b ' v ! ~ { ] c / ( d _ : * [ 6 k | e f 8 O P Q G Q Q G Q H g m J ",
+" K u u u o p h i 0 0 a 3 4 5 b R v ~ r S ^ # s % d _ w x T 6 | | e 8 8 G G Q N G Q N G N H m ; J ",
+" A u u U V W X Y Z ` ...+.@.#.$.%.! ~ { C ^ L D % E _ < x 6 k | | f G O Q G G G N G G Q G G H m ; J ",
+" u u u &.*.X =.Z -.;.>.,.'.).!.~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.0.a.a.b.c.d.G N G N N m m ; ",
+" u u o &.W X =.Y ` e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C.D.C.E.F.G.H.I.J.K.L.Q Q G G M.N.N.1 ",
+" n o o o *.X Y Z -.;.O.P.Q.R.S.T.U.V.W.X.Y.Z.`. +.+++@+#+Z.$+ +.+++@+#+Z.%+ +&+@+*+=+-+;+>+,+'+Q Q - - - )+!+ ",
+" o p p p ~+Y Z ` .{+]+^+/+/+(+_+:+:+<+[+}+|+1+2+2+}+3+}+|+1+2+2+}+[+}+|+1+2+2+4+5+6+7+8+9+0+a+'+a+b+b+c+- )+ ",
+" h p h h i Z -.` d+ .e+f+g+h+i+/+:+j+k+l+m+n+o+p+q+r+s+m+s+t+u+q+v+l+m+s+o+u+w+q+x+y+z+A+B+C+D+E+'+F+G+G+b+b+b+)+ ",
+" 9 h i i i 0 H+I+ .J++.K+L+M+N+/+O+P+Q+R+S+T+U+V+W+X+Y+Z+`+ @.@+@@@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@]@^@/@(@_@G+G+b+1 ",
+" 0 i 0 0 0 q J+:@<@+.[@}@|@1@2@3@4@5@6@7@8@9@0@a@b@c@d@e@f@g@h@i@j@k@l@m@n@o@p@q@q@r@s@t@u@v@w@]@]@]@/@x@/@/@(@_@y@z@ ",
+" 0 0 q q a a :@A@+.[@@.B@C@D@E@F@G@H@p+I@J@K@L@M@N@O@P@Q@R@S@T@U@V@W@X@Y@Z@`@^ #.#+# #@###$#%#&#%#*#=#-#;#x@/@/@(@_@ ",
+" 2 a a a a B 3 +.>#[@B@,#B@$.'#)#!#~#{#]#y+^#/#(#_#:#<#[#}#|#S |#1#2#3#`@4#5#6#7#8#9#0#0#9#0#a#}#}#b#c#d#d#=#e#;#;#f#(@)+ ",
+" 3 3 3 3 4 4 j j 5 b ' ,#%.%.g#h#i#j#k#l#m#n#o#p#q#r#s#t#t#u#v#w#x#y#z#A#B#C#D#E#F#G#a#a#H#a#}#I#|#J#J#J#J#K#d#=#e#;#x@(@ ",
+" L#4 4 j j 5 5 b b b ' ' ) g#g#M#H#N#O#P#Q#n#R#p+S#T#U#V#W#X#Y#A#Z#`# $.$F#+$@$#$$$%$&$A#*$a#*$a#=$1#=$1#1#1#J#K#K#d#e#;#;#z@ ",
+" , 5 b b b b b ' ' R ) v ! g#M#H#a#-$;$>$,$'$)$H@R#!$~${$]$^$/$($_$_$:$<$[$}$|$[$1$2$3$4$5$*$6$B#7$7$5$7$y#=$1#1#J#K#d#=#e#z@ ",
+" ' ' ' ' ' ' ' ) v v ! ! ~ H#a#H#0#8$9$0$a$b$c$d$4@e$f$g$h$i$E#j$k$l$m$m$n$o$p$q$r$s$t$u$v$, j$j$j$j$j$j$, 7$7$=$1#J#w$x$d#y$ ",
+" ) ) ) ) ) v ! ! ! ~ ~ r { a#0#&#0#z$A$B$C$D$E$F$G$|+H$I$J$K$L$2$M$M$N$O$P$o$Q$R$S$T$U$V$W$X$[$v$v$[$[$[$j$, , 7$y#=$1#Y$x$d# ",
+". ! ! ! ! ! ! ~ ~ ~ r { { C ] 0#%#]@Z$`$ %.%+%@%#%$%%%[+[+&%*%=%-%;%>%,%s$'%)%!%~%{%]%^%/%(%_%:%<%O$v$v$v$[$[$j$, 7$7$=$1#Y$[%y$",
+"+ ~ ~ ~ ~ r r r { { S C ] ^ @ }%}%}%%#|%1%2%3%4%5%6%7%8%9%0%a%b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%(%)%_%_%:%<%O$v$v$[$[$j$, 7$q%1#Y$r%",
+"@ { { { { { { C ] ] ^ ^ c # L s%D D s%}%t%2%u%v%w%x%y%z%A%3@B%C%D%E%F%i%G%H%I%J%l%p%K%2 L%M%m%N%O%P%Q%_%_%:%O$v$v$[$j$, 7$q%1#[%",
+"@ ] ] ] ] ] ] ^ ^ c # L / s%D % % t s%]@R%r%S%T%U%V%W%X%Y%Z%`% &.&+&@&#&$&(%%&&&*&=&-&-&;&>&&&,&N%'&'&P%Q%Q%_%:%O$v$)&[$, 7$q%Y$",
+"# ^ ^ c c c # # L / s D t % M d d % !&A$|%~&1#{&]&[$^&/&(&_&:&<&[&}&|&1&2&3&4&5&6&7&8&9&0&a&b&c&2 d&d&e&'&P%Q%Q%:%O$v$)&[$j$7$1#",
+"$ / / / / s s D D ( % % M f&E '+E+g&h&i&j&S%=$q%k&l&m&n&o&p&q&r&s&t&u&v&w&x&y&z&A&9&B&C&D&E&F&G&c&H&H&2 2 I&'&P%Q%_%O$J&)&[$, q%",
+"% ( ( ( ( t % % M d d E _ _ _ '+K&]@L&M&N&2%O&a#D#P&Q&R&S&:& &3@T&U&V&W&X&Y&Y&-&Z&`& *.*+*@*#*$*b&G&G&c&H&2 d&I&P%Q%_%O$J&)&%*7$",
+"& % % d d d d E E _ _ _ : w _ d &*$ **t%0#[%=*-*;*>*,*'*)*!*~*{*]*^*/*>&>&(*_*:*<*[*D&}*|*1*2*:*`&3*4*G&G&c&H&2 I&'&Q%_%O$J&)&, ",
+"* _ _ _ _ _ _ _ _ : w < < * 5*6*&*7*8*9*0*a*a*b*c*d*e*f*g*h*i*j*k*l*(*m*n*o*p*q*r*s*t*u*v*w*x*y*:*:*:*3*4*z*G&A*2 B*P%Q%_%O$J&%*",
+"= : : : : : w < < * x x [ C*D*f&]@]@9*E*}#K#F*G*H*I*e$h+:&J*K*L*M*N*-&O*D&D&P*Q*1*r*R*S*T*U*V*W*X*X*Y*:*:*3*z*A*A*2 Z*P%Q%`*J&%*",
+"- < < < * * x x x [ T 6 6 C*D* =.=+=@=c##=$=%=&=*===O+-=;=>=,='=)=8&!=#*~=q*Q*{=]=^=/=(=_=:=<=[=}=}=}=v*Y*:*3*z*A*A*2 Z*Q%Q%O$|=",
+"; [ [ [ [ [ } 6 6 6 6 k T < 1=2=6*+=3=4=5=6=7=8=e$G@9=0=a=b=c=h%d=e=O*f=1*g=1*h=i=j=k=l=m=n=o=p=p=p=[=}=g=X*P*2*z*A*H&B*Z*Q%`*|=",
+" } 6 6 6 6 6 7 k k | a+T = q=r=s=. t=u=v=w=d$<+ &x=y=z=A=B=C=D=E=N*F=F=3*P*G=x*H=I=J=K=L=M=N=O=]=]=]=p=[=}=v*P*P=z*(*2 B*Q%`* ",
+" | 7 7 k | | | Q G C*k Q=6 6 R=S=T=U=V=W=X=Y=:+Z=`= -.-p%+-d=d=D=4*@-#-$-%-&-*-=---;->-K=,-'-)-!-~-~-]=p=[=}=v*2*{-]-(*B*Z*^- ",
+" 1 | | | | | | e e /-(-6 6 T 2=_-:-<-[-p+R#}-|-1-2-3-4-5-6-7-B@@.F=F=E&8-9-i=0-a-b-c-d-e-f-g-h-i-!-K ~-]=p=[=}=Y*2*z*(*2 B*j- ",
+" 1 | e e e e f f k-f l-e C*T m-n-o-p-q-r-p+s-t-u-v-w-x-y-z-e&A-@.F=B-C-q*D-*-E-F-G-H-I-J-K-L-M-N-O-P-K Q-]=p=R-v*2*{-A*2 B*j- ",
+" 8 f f f f 8 8 f Q G = e S-T-U-V-t+]#q-W-X-Y-Z-`- ;.;d&+;@;D=@.F=4*#;r*$;}=%;&;*;=;-;;;>;,;M-';);!;~;K Q-{;[=}=Y*P=]-(*]; ",
+" 1 f 8 8 8 8 f f ^;O 8 /;(;_;:;4+<;o+[;};|;1;2;2;3;4;5;6;7;8;9;0;a;b;c;d;e;f;g;h;h;i;j;k;l;m;n;i-o;p;q;~-Q-p=}=v*P=]-(*|= ",
+" 8 8 8 8 8 r;s;8 (-t;u;v;w;1+5+Y=x;y;z;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;W;X;Y;Z;`; >.>+>@>#>$>{;%>v*2*{-(* ",
+" g 8 l l l s;l 8 &>*>=>->1+;>5+1+>>,>'>)>!>~>{>]>j+^>/>(>_>:><>[>}>|>1>2>3>3>4>5>6>7>8>9>0>a>b>c>d>e>f>f>{;%>v*2*{-g> ",
+" 1 l l l l l l ^;s;h>i>j>k>l>l>5+1+m#[+m>1+n>(+o>(+/+p>g*/+(+q>/+r>s>t>u>v>w>v>x>y>z>A>B>C>D>E>F>G>e>f>f>{;%>v*2*{-^- ",
+" m l l I l l m g H>I>J>K>L>M>w;N>O>P>Q>Q>P+{>]>j+R>/>(>_>S>T>U>V>W>X>Y>Z>`> ,.,+,@,z>z>#,$,%,&,!-*,=,-,{;%>v*2*g> ",
+" g I I I I ;,F l >,,,',),C.!,~,{,],^,/,(,_,:,<,[,},H;|,1,2,3,4,5,6,7,8,9,0,a,b,c,d,e,f,g,h,i,f>e>f>f>{;j,v*{- ",
+" 1 I I I I I m I l k,l,m,n,1.o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,n #>f>f>=,p=R-v*^- ",
+" T,I N.N.I ;,U,V,W,8 X,Y,2=Z,`, 'B$.'+'@'($#'$'P%d&H&G&%'&'*'='-';'>',''')'!'~'{']'^'/'('_'!-f>:'=,%>v*P= ",
+" N N <'m [';,I ;,}'|'1'2'(@3'h&d#a*4'5'6':$P$7'd=8'9'y&0'Y&a'$*b'2*s*c's*p=d'e'c-f'{;K=K=#>f>f>g'g'h' ",
+" J H G W,i'j'T,N.^;k'6 l'Y,/@m'n'o'x#5'`-#'|$p'd=8'D=q'#&r's'b&O*~=8-t'W*u't*v'w'b-x'y'$>z'=,=,<@A'B' ",
+" J ; W,C'F m D'E'F'G'Y,H'I'J'=#K#K'w%L'M'N'd=B@8'A-a'O'N*&'&'P'F&Q'2*+*R'S'T'U'V'V'W']=O=g'g'X'B' ",
+" J ; Y'T,; Z'l `' ).)l'+)+ c#K'@)#)$)%)&)p',#d=d=A-c=O'Y&3&&'(**)=)b'2*t'.*-)}=;)>)T':',)h'') ",
+" )); !); U,~){) )])Y,^)/)()[#s#_)Z#[$v$:%Q%P%I&2 3&:)M%<)<)<)b&Z&*)*)[)Q*})D-}=|)1)g'h'B' ",
+" J 2)1 U,N.M.3)G+_@4)5)6)[#7)8)9)[$v$O$:%Q%P%I&2 0)I&M%a)b)z*c)d)e)f)f)g)-)f)h)i)j)k) ",
+" 1 l)U,M.m)b+G+n)5) 'n'7)y#7$j$[$v$O$_%Q%'&B*2 0)#&M%r'<)z&d)d)o)o)g)p)f)v*P= ",
+" !+q){)3)3)G+n);# 'r)J#=$7$, j$)&v$O$_%Q%P%Z*2 ,&s)t)M%r'a)a)z&d){-u){-^- ",
+" )+b+y@(@f#;#e#d#w$1#=$7$, [$)&J&O$_%Q%P%Z*B*2 v)M%3&w)w)(*(*x)g> ",
+" 1 z@_@(@x@;#=#x$Y$1#q%7$, [$)&J&O$_%Q%Q%Z*B*B*2 2 (*(*(*g>^- ",
+" )+(@;#e#d#x$Y$1#q%7$j$[$)&J&O$`*Q%Q%Q%Z*B*B*];|= ",
+" z@z@y$d#[%Y$1#q%7$, %*)&J&J&O$`*`*^-j-j- ",
+" y$r%[%Y$1#q%7$, %*%*|=|= "};
diff --git a/arts/builder/pics/Synth_PLAY.xpm b/arts/builder/pics/Synth_PLAY.xpm
new file mode 100644
index 00000000..3ad46f6e
--- /dev/null
+++ b/arts/builder/pics/Synth_PLAY.xpm
@@ -0,0 +1,316 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 245 2",
+/* colors */
+" c #B1B1B1",
+" . c #BFBFC2",
+" X c #ADADAD",
+" o c #A9AAB3",
+" O c #ABABAB",
+" + c #323E7D",
+" @ c #5F6792",
+" # c #71789D",
+" $ c #2F3A7A",
+" % c #3E4C8C",
+" & c #A5A5A5",
+" * c #3A4488",
+" = c #273272",
+" - c #8D93B5",
+" ; c #78787C",
+" : c #253070",
+" > c #616B97",
+" , c #344082",
+" < c #232E6E",
+" 1 c #313C7F",
+" 2 c #B0B5CA",
+" 3 c #1F286A",
+" 4 c #959595",
+" 5 c #1C2667",
+" 6 c #5F6BAC",
+" 7 c #696A6D",
+" 8 c #374288",
+" 9 c #8D8D8D",
+" 0 c #36417D",
+" q c #6F79AB",
+" w c #43518D",
+" e c #1F2A6D",
+" r c #1E286C",
+" t c #414F8B",
+" y c #2D3774",
+" u c #1A235E",
+" i c #9599AF",
+" p c #D1D2D6",
+" a c #64666B",
+" s c #475394",
+" d c #777777",
+" f c #767DA1",
+" g c #536299",
+" h c #2F3B79",
+" j c #8E8F94",
+" k c #2A3574",
+" l c #5D68A6",
+" z c #4B5891",
+" x c #50598C",
+" c c #273171",
+" v c #575D7F",
+" b c #222D6C",
+" n c #212B6B",
+" m c #303B7D",
+" M c #404B90",
+" N c #1D2767",
+" B c #3C478C",
+" V c #4C5A95",
+" C c #38447E",
+" Z c #38427E",
+" A c #343E7A",
+" S c #858CAF",
+" D c #42508B",
+" F c #2E397E",
+" G c #1D276A",
+" H c #404E89",
+" J c #1C2769",
+" K c #303A76",
+" L c #2C377C",
+" P c #3E4C87",
+" I c #C7C7C8",
+" U c #AFB0B7",
+" Y c #E4E5EB",
+" T c #29326F",
+" R c #384481",
+" E c #DCDDE3",
+" W c #303C79",
+" Q c #3E4C8A",
+" ! c #3D4A89",
+" ~ c #414B83",
+" ^ c #3A4886",
+" / c #686971",
+" ( c #7B84A8",
+" ) c #515C8C",
+" _ c #656F99",
+" ` c #7880A5",
+" ' c #4A578F",
+" ] c #424C91",
+" [ c #202A69",
+" { c #3E488D",
+" } c #2C3878",
+" | c #1B2464",
+". c #797A7E",
+".. c #3A477F",
+".X c #9D9D9E",
+".o c #39457E",
+".O c #47558F",
+".+ c #D0D0D0",
+".@ c #212C6D",
+".# c #1E286A",
+".$ c #CACACA",
+".% c #283277",
+".& c #3B4783",
+".* c #253074",
+".= c #485793",
+".- c #BEBEBE",
+".; c #222C71",
+".: c #44538F",
+".> c #BCBCBC",
+"., c #6974B0",
+".< c #BABABA",
+".1 c #1E286D",
+".2 c #3E4D89",
+".3 c #848AA6",
+".4 c #5F6585",
+".5 c #4F599D",
+".6 c #B4B4B4",
+".7 c #B2B2B2",
+".8 c #394784",
+".9 c #ABADB5",
+".0 c #34417F",
+".q c #ACACAC",
+".w c #87878B",
+".e c #58649F",
+".r c #AAAAAA",
+".t c #414D8F",
+".y c #2D3978",
+".u c #6F6F70",
+".i c #57608A",
+".p c #A0A0A0",
+".a c #666871",
+".s c #283373",
+".d c None",
+".f c #CFD0D8",
+".g c #364184",
+".h c #465197",
+".j c #242F6F",
+".k c #BBBCC1",
+".l c #9A9A9A",
+".z c #313D7F",
+".x c #989898",
+".c c #A8A8AB",
+".v c #4D5480",
+".b c #52609C",
+".n c #A3A4A6",
+".m c #4E5E98",
+".M c #2B3579",
+".N c #6B739A",
+".B c #293577",
+".V c #293377",
+".C c #273175",
+".Z c #495893",
+".A c #394680",
+".S c #475691",
+".D c #717482",
+".F c #E0E1E5",
+".G c #42508C",
+".H c #DADBDF",
+".J c #1D276B",
+".K c #979DBB",
+".L c #8088AB",
+".P c #2C3673",
+".I c #5C6281",
+".U c #242F75",
+".Y c #3C457C",
+".T c #33407D",
+".R c #747474",
+".E c #41508E",
+".W c #B8B9BA",
+".Q c #646FAD",
+".! c #2E3A78",
+".~ c #808083",
+".^ c #2C3876",
+"./ c #2B3675",
+".( c #293473",
+".) c #384485",
+"._ c #242E6E",
+".` c #45518B",
+".' c #424F88",
+".] c #465082",
+".[ c #414D87",
+".{ c #2D387A",
+".} c #9FA2AB",
+".| c #2B3678",
+"X c #384288",
+"X. c #171F57",
+"XX c #343E84",
+"Xo c #DEDEE2",
+"XO c #353F7B",
+"X+ c #2F3A7F",
+"X@ c #1C2669",
+"X# c #2F3975",
+"X$ c #3E4B87",
+"X% c #D7D8DB",
+"X& c #C4C4C5",
+"X* c #4A5996",
+"X= c #36437F",
+"X- c #48548A",
+"X; c #202A70",
+"X: c #F1F1F1",
+"X> c #1F2A6F",
+"X, c #515BA0",
+"X< c #B4B4B5",
+"X1 c #3B4987",
+"X2 c #4C579B",
+"X3 c #7D7D7F",
+"X4 c #B2B2B3",
+"X5 c #3E4880",
+"X6 c #384584",
+"X7 c #495598",
+"X8 c #364382",
+"X9 c #5661A8",
+"X0 c #434F92",
+"Xq c #374079",
+"Xw c #53597A",
+"Xe c #A5A7B0",
+"Xr c #3E498D",
+"Xt c #5966A4",
+"Xy c #1E296A",
+"Xu c #1D2769",
+"Xi c #C9C9C9",
+"Xp c #929293",
+"Xa c #3B458D",
+"Xs c #3D4A85",
+"Xd c #4C5C97",
+"Xf c #E6E7EC",
+"Xg c #D4D5D7",
+"Xh c #C3C3C3",
+"Xj c #C1C1C1",
+"Xk c #232D72",
+"Xl c #465491",
+"Xz c #455490",
+"Xx c #212B70",
+"Xc c #34407C",
+"Xv c #43528E",
+"Xb c #CCCDCF",
+"Xn c #1F296E",
+"Xm c #323E7A",
+"XM c #1E296D",
+"XN c #525EA0",
+"XB c #313C79",
+"XV c #B7B7B7",
+"XC c #676A79",
+"XZ c #2A3472",
+"XA c #7C7C7D",
+/* pixels */
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d c.%.V.V.%.C.U.U.;XnXy N.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.P +X 8XXX+ L L.V.%.U.UXk.;.;XxX;Xn | u.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.dX1X0 M BX 8XXX+ L L.V.%.U.UXk.;.;XxX>X>XnXn r u.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d ZX,.5X7.h MXaX XXXXX+ L L.V.%.U.UXk.;.;XxX>X>XnXM.1.1 rX@ u.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.dX9X9X,.5X7X0 MXaX XXXXX+ L.M.V.%.U.UXk.;XxXxX>XnXnXM.1 r r r.J 5.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.dXd 6 6X9X,X2.hX0 MXa 8XXXXX+ L.M.V.C.*.UXk.;XxXxX>XnXnXM.1 r r.J.J.JX@ u.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.,., 6X9X9X,X2.h ] {Xa 8XX 1 F L.M.V.s = c :.;XxX;X>XnXnXM.1 r r.J.J.J G G 5.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.`.,.,.Q 6X9XN.5X7.h ] {Xa 8XX 1 F L m 0XOXOXB K.s.;XnX>XnXn.1 r r r.J.J G G G G 5X..d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d z.,.,., 6X9X9X,X2.hX0 MXaX 8XXX+ m Z x # f `.N @ ~ c.@XnXnXM.1 r 3 [ G G G G GXuX@ 5X..d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d V.,.,.,.Q 6X9X9X,X2.hX0 MXa 8XX 1X+ Z.' (.fX% E .Xe @ y.@XnXnXM r e._ T b rXu G GXuX@X@ 5X..d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d z.,.,.,.Q 6X9X9X,X2X7.h M {Xa 8XX , R.i ( U E.f I o j.4 y.@XnXnXM 3._Xq ).Y T [XuXu JX@X@ 5 5X..d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.`.,.,.,.Q 6X9X9XN.5X2.hX0 MXaX XXXX.&X-.L.f EXf.$ X j. Xw.P nXnXn.1 [ T ) - @Xq T.#XuXuXuX@ 5 5 5X..d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.,.,.,.Q 6 6X9XNX,X2.hX0 M {Xa 8.gX$ @ S 2 EXo.FXh &.w.RXwX# T.@ e r.@._.Y @ @ @X5 T n.# GXuXu 5 5 5.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.,.,.,.Q 6X9X9X9X,X2X7.h ] MXaX .gX$ ' S.f E YXo.H.>.X.~ / v KXBXm.(Xx.@.@.PXq @ i @XqXZ e 3 r.#.#XuXu |.d.d.d.d.d.d",
+".d.d.d.d.dXd.,.Q 6 6X9X9XNX,X2X7.hX0 MXaX *.[ > S 2X%Xb ..$XgXV.l.~ / vXqX- _X-Xm.( < c y.] @ > _.] c.@ e e 3 3Xy.# u.d.d.d.d.d",
+".d.d.d.d.d 6 6 6X9X9X9XNX,X2X7.hX0 M B *X H z S.fX%.H.W.xX4Xb.6.l.~ / v.Y >.K fX- A : : :X#.Y.N.9 @ K._.@.@.@ n nXyXu.d.d.d.d.d",
+".d.d.d.dX9 6X9X9X9XNX,.5X2X7 sX0.tXrX1 !.G > S 2.H IX4.p 9.qXbX4.l.~ /Xw A.v _ # ( x.y = :XZXq _.9 _XqXZ < < < <.@ n nXu.d.d.d.d",
+".d.d.d ZX9X9X9XNX,X9 lXtXt.e.b.b V V z z ) -.f.H.H.6 9.wX3 &.$.7.l.~ /.v yXq ~ # 2.N 0.(.C.sXB @.9.NX5 K c :.j.j < <.@.@ |.d.d.d",
+".d.d.dX,X,X,X,.5XN q.K.K.K.K.K.K.K - - -.K 2 EXbX<.xX3X3XA.n.$ .x.~ /Xw K A.o.N 2 f.[XB.s./.y.].N.N.N.]X# c c : :.j < b [.d.d.d",
+".d.d.d.5.5X2X2X7XN -X% EXfXfXfXfXfXf YXfXfXf Y.W 9.~.R dXA.pXi .x.~ /XwXm AXO _ 2.L ).&.|.|.BXO ~.N.9 _XqXZ.s = c : :.j <.d.d.d",
+".d.dX1X7X7.h.h s.b - E YXf Y.FXoXo E.H.H EXoXoXVXp.wXA.~.w &Xi .x.~ /Xw AXm $X- # `.L ) +.y.|XBX5 @ i @ Z.P k.(.s = c : : N.d.d",
+".d.dX0.hX0X0 ] ].m.KXfXf YXoX%XgXg p.+.+.+Xg.HXV 4 9.w.w 9.q.$ .x.~ /XwXOXm.{ Z.] f 2.N.& $.{ K.o.i (.i.o.^.|.B k.(.s = c.j.d.d",
+".d.P M M M M {Xr V -Xf.FXoXg.+Xb.$Xi I IXiXgXo p IXj.-XjXj.$.+.6.x.~ /Xw 0 W.{XO ~ _.K _X5XB m W.o @ i > ~Xm } }././ k.(.s c [.d",
+".d + BXaXaXaXa *Xl -XfXoXgXbX&XhXj.-.-.-Xj p YX:X:X:X:X:X:XfX%XV.x.~ /Xw Z h m WX5 @.L @ ~Xm mXB.. _ 2 #.].o h.y } }./ k.(.s [.d",
+".dX X X X 8 8.).` S YXoXg.$XjXj.-.-.>.-.-.+.F YXfXfXfXfXfXoXgXV 4X3 /Xw.oXB.z +X5 >.K.N.' Z +.TX= x # # # xXc h.!.y }.^./ k =.d",
+".d 8 8XXXXXXXX ,.[ S Y E.+XiXj.-.-.<.<.<.-XbXo.H.H.HX%X%X%Xg p.6 4X3 /Xw.o +.z.TXs.N 2 fX- ~ , ,.0X5X- # 2.NX5Xm $ $.!.y.^./ k.d",
+" cXXXXXXXXXX 1 +X$ S Y.H.+ I.-.>.<.WXV.W.<XiXgX& X.c O X.-Xb 4X3 / v.&.T ,.0.8 ) f f f ).&X8X8...' _ i _ ~Xm + W $.!.y.^./XZ",
+".%X+X+X+X+X+ F mXs.L Y.HXbX&.<.<.WXVXVXV.<X&.+.r.wX3 dXA.~ &X& X 4X3 / v.&.0X8X8.).[ x f 2 #.' RX8X=.[ @.3 @.[ 0 + +Xm W h.y.y k",
+".V L L L L L L.{.&.L YX%.$Xj.WXVXVX<.6XV.WXhXb &X3 d.u.RXA.pXh.q 4X3 / vXs.0X8.).)XsX-.N.K.N.` R.).A.' @.L @.' 0.0.T + + W h.!.^",
+".V L L L.M.M.M.| R (.FX% I.-XVXVX<.6X4X<XVXj.$.p d.u a.u.R.lXj O 4X3 / vXsX8.).).).&.` > S >X-.8 ^.&.' @.3 >.`X=.0.0.T +Xm W h.^",
+".%.V.V.V.V.V.%.B Z (.FXg I.-X<.6X4.7.7.6XVXj.$.p d.u a.u.R.lXj.rXpX3.a v.[ R ^ ^X1.&.` > S _.OXsX1.&.` @.L >.`.AX8X8.0.T + + W.!",
+".C.%.%.%.%.C.C.s 0 (.FXgX&.>.6X4.7 X4X<.-Xi.p d.u a.u.R.lXj.rXpX3.a v.[.8X1X1 !XsX- > S _ 'X$ !XsX- >.3 >X-.AX6X8X8.0.T +Xm h",
+".U.U.U.U.U.*.U = A `.F pXj.<.7 .7.6.- I.X.R.u a 7.R.lXj.rXpX3.aXw.[.8 ! ! QX$.O > S _ z.[ Q PX- >.3 >X-.&.8X6X8X=.0.0 + W",
+".U.U.U.U.U.U.U :Xm ` E pXj.W X4.- I.X.R.u a 7.R.xXj.rXpX3 /Xw P.& Q % %.2 ' _ S _ z H.t.[ ' > S _X-Xs ^.8X6X8X=.0XcXm",
+".;XkXkXkXkXkXk :XB f E pXjXV X X .7.- I.nX3 d.u dXA.pXj.rXp. .a v.'X1 % %.t.` ) #.K # z D.E H ' _ S _ 'XsX1 ^.8X6X8X=.0 +",
+"Xn.;.;.;.;.;.;.j K f E p.-XV X X X X .7.-Xi.c.w.~XA.~.w &Xj.rXp. .a.I.` P %.t.E z g ( 2 f z wXv D z _ S _ z PX$X1 ^.8 RX8.0Xc",
+"Xy.;.;.;XxXxXx bX# # E.+.-XV X X X.q.q X Xj.+ I.>.WXV.W.<XjXi XXp. .a.IX-.2.E.E.O > ( ( ( >.ZXl.:.O ) #.K.NX- P QX$X1 ^.8 RX=Xc",
+" NXxXxXxXxXxX; nXZ.N EXb.-X< X.q.q O O X X&X%.FX:X:X:X:X:Xo.+ Xp. .a.I.O H.E w V ` 2 ( g VXlXlXl V g ( 2.NX-.[ Q Q !X1.8.A RXc",
+".dX;X>X>X>X>X>.@ y # EXb.>.6.q.q O O.r X XjXg.H.F.F.FXoXoXgXb Xp. .a.I.O DX0.:.m f.K f g z.=.Z V > ( ( ( @.: t t Q PXs ^.8 R.d",
+".dXnX>X>XnXnXn.@ K ` EXb.<X4.q O O.r.r.q Xj.+.+.+.+.+.+.+Xb.$ XXp. .a.I '.GXl.O g # -.N g.ZX*.Z g ` 2 ( g z.: w.G t.2X$X1.8.A.d",
+".d |XnXnXnXnXn b K f E.$XV X & & & & &.c O.<.$.W.c &.p.n &X<X&.rXp. .a.4 '.:Xl z g `.K f g zX* V g f.K f g 'Xz.: w t Q PXs ^Xm.d",
+".d uXnXMXMXMXM nX# f.H I .r.p.p.p.p.p.n &X<Xh.pX3 d.u dXA.X.- &Xp. .a.4 '.SXl.m.e.L 2 ( g VXd V.e # -.N.m.OXlXzXv.G t QX$ ^Xq.d",
+".d.d r.1.1.1.1 [ y.N.kXe j.w.w.~.~.~.~.w 9.n.W.lXA.R 7.u d.x.- & 9. .a.4 ' z V _.L -.K q.b.m.m.m.e `.K # g.O.SXl.: w t.2X$.&.d.d",
+".d.d u.1 r r r [.P.4.} j.D.u / / / / /.u d j 4 ;.u a 7.u 4.> & 9. .a.4 z V.m ( 2.K q.e.m.m.m g >.L 2 ` g z.=Xl.: w t.2 PXq.d.d",
+".d.d.d r r r rXy._.Y.i vXwXwXwXwXwXwXwXw v.D j j 9X3.u.u.u 4.< & 9 ;.a.I z.m g.L 2 - l g.m.b.e.N.L.L.L _.m.Z.=.SXzXv.G H P.d.d.d",
+".d.d.dX@ r.J.J G r._ T TXZ.P yX# K KXmXq.Y v.D.w & 9 d.R.u 4.< & 9 ;.a.I '.m @.L 2.L.e.m.b.bXt.L 2.L > gXdX*.Z.SXzXv.G HXs.d.d.d",
+".d.d.d u.J.J.J.J G G 3 3 [ n b._ : =XZX#XO.] v.D.w 9 9.~ ;.l.< & 9 ; a.4 ) > ( S.K q.b.m.b g l.L 2.L.e.mXdX*.Z.SXzXv.G H...d.d.d",
+".d.d.d.d 5.J.J G G G G G r e.@.j : =.s.B } 0X5 v.D.w.nXp.~.p.> & 9 ; a.4 g ` 2 - q.e.m.m.b.e _ S 2 (.eXdXdX*.Z.SXzXv.G P.d.d.d.d",
+".d.d.d.d.dX@ G G G G G G r e.@.; :.*.s.B.| W 0.] v.D.w j.x &XV.p 9 ; a.4 ) _.L q.e.b.m.b.e.N (.L.L _ gXdXdX*.Z.SXz w H.d.d.d.d.d",
+".d.d.d.d.d u G G G GXu G r e.@ < :.*.s.B.|.y $ Z ~.I.D j X .X 9 ; a.4 z g.e.mXdXd.m g > (.K ( >.e.mXdXdX*.=Xl.: w...d.d.d.d.d",
+".d.d.d.d.d.d 5 GXuXu JXu.# e.@ < : c.C.B.| }.!Xm.o.v.I.D j.X .X.w d a.4 ' ' z.=X* V.m > ` ` ( _ g.mXdXdX*.Z.S.O.: H.d.d.d.d.d.d",
+".d.d.d.d.d.d.d 5X@X@X@Xu G 3.@ <.j :.C k.B }.{ $ +...].I.D j X.l.w d a.I ' wXl.=.Z z g f.K ` > g.mXdXdX*.Z.=.SXz D.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.dX. 5X@X@X@Xu r e.@.j : =.(.B.|.y $ mXc...v.I.D.w.~ d / a.IX- DXlXl.=.=Xd > # > gXdXdXdX*.Z.=.SXz w.Y.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.dX. 5 5 5Xu.# e.@ < : c.s k.|.{ $ m +.0X5.] vXC.a a a a vX- D.:XlXl.S.= V.mXd VX*X*X*.Z.=.SXl w.Y.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.dX. 5 5 5.# 3.@ <.j c.s k.| }.! $ + + 0X5.v v v v v v x.` D w.:XlXl.S.S.S.Z.=.Z.Z.=.S.SXz w.Y.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.dX. 5 5Xu 3 n <.j : =.(.B }.y $ m +.T.0.A ~ ~ ~.[.'.' Q t.G w.:XzXlXl.S.S.S.S.SXl.OXz w.Y.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.dX. 5XuXy n.@ < : c.s k./ }.! $ + +.0.0 0 C.A.&.&XsX$ Q t.G wXv.:.:XzXzXzXzXz.:.: D.Y.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d |.#Xy n <.j : =.(./ }.y $ W +.T.0X8X8X6.8 ^X1X$ Q Q t t.G w wXvXvXvXv w w H.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d uXu n.@ < : c.s k./ }.! $Xm +.T.0X8X8X6.8 ^X1 ! P.2 Q t t t.G.G.G.G H...d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.dXu.@ b.j : =.( k.^.y.! W + +.T.0X=X8X6.8 ^X1XsX$ P Q.2.2 H H H P.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d | [ < : c.s.(./.^.y h WXm +.T.0X=X8 R.8.8 ^X1XsX$X$ P PXs...d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d N.j c.s k./.^.y h W + +.0.0X=X8 R.A.8.8 ^ ^.&Xq.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d [ [ = k./.y.! h WXm +Xc.0.0X= R R.AXmXq.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d",
+".d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.dXZ k.^.^.! h WXm +XcXcXc.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d"
+};
diff --git a/arts/builder/pics/Synth_PLAY_AKAI.xpm b/arts/builder/pics/Synth_PLAY_AKAI.xpm
new file mode 100644
index 00000000..a7cedce2
--- /dev/null
+++ b/arts/builder/pics/Synth_PLAY_AKAI.xpm
@@ -0,0 +1,317 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 246 2",
+/* colors */
+" c #27326F",
+" . c #68D14E",
+" X c #303E7B",
+" o c #2E3A79",
+" O c #3B4889",
+" + c #2A3675",
+" @ c #293474",
+" # c #51FD0F",
+" $ c #273272",
+" % c #374285",
+" & c #4FFB0D",
+" * c #4EFB0C",
+" = c #44A73B",
+" - c #323E80",
+" ; c #434E94",
+" : c #202A6B",
+" > c #3E4A8F",
+" , c #1C2667",
+" < c #4BCA27",
+" 1 c #3D4B84",
+" 2 c #52F913",
+" 3 c #375074",
+" 4 c #45538F",
+" 5 c #1F2A6D",
+" 6 c #2F3A80",
+" 7 c #323D79",
+" 8 c #1E286C",
+" 9 c #414F8B",
+" 0 c #46ED07",
+" q c #46EB07",
+" w c #4CB935",
+" e c #3B4985",
+" r c #4C5999",
+" t c #4B5998",
+" y c #1A235E",
+" u c #3A5970",
+" i c #43DC0E",
+" p c #44CF19",
+" a c #384582",
+" s c #232E74",
+" d c #445191",
+" f c #323F7C",
+" g c #656FB8",
+" h c #6F76A4",
+" j c #408551",
+" k c #5CFE19",
+" l c #538967",
+" z c #56FE13",
+" x c #374384",
+" c c #46B332",
+" v c #303B7D",
+" b c #1D2767",
+" n c #2B3778",
+" m c #5BE22F",
+" M c #44E30B",
+" N c #4AF40A",
+" B c #42508B",
+" V c #1E296B",
+" C c #51629D",
+" Z c #48F208",
+" A c #1D276A",
+" S c #50609C",
+" D c #404E89",
+" F c #47EE07",
+" G c #2A357A",
+" H c #283378",
+" J c #29366F",
+" K c #263176",
+" L c #242F74",
+" P c #465492",
+" I c #222D72",
+" U c #202B70",
+" Y c #43508F",
+" T c #41508D",
+" R c #30496F",
+" E c #3E4C8A",
+" W c #52955B",
+" Q c #2D3876",
+" ! c #45EA08",
+" ~ c #45E808",
+" ^ c #5D68AF",
+" / c #3C4F7E",
+" ( c #4C569B",
+" ) c #394685",
+" _ c #4B845E",
+" ` c #4EEC14",
+" ' c #404E8F",
+" ] c #1E2867",
+" [ c #293475",
+" { c #283474",
+" } c #253071",
+" | c #4FF90E",
+". c #475E85",
+".. c #4A756A",
+".X c #4DF90C",
+".o c #4BF50A",
+".O c #4AF509",
+".+ c #1E286A",
+".@ c #49F108",
+".# c #1C2668",
+".$ c #4BD51E",
+".% c #4D5D98",
+".& c #293478",
+".* c #4C5B97",
+".= c #45D318",
+".- c #3B4783",
+".; c #273276",
+".: c #5B67A9",
+".> c #263075",
+"., c #485793",
+".< c #222C71",
+".1 c #44538F",
+".2 c #202A6F",
+".3 c #1F2A6E",
+".4 c #42518D",
+".5 c #1D286C",
+".6 c #699088",
+".7 c #45ED07",
+".8 c #3D4B88",
+".9 c #406B63",
+".0 c #4B5B99",
+".q c #34417F",
+".w c #505BA1",
+".e c #3C498A",
+".r c #6175A1",
+".t c #4EA645",
+".y c #45D814",
+".u c #3A5E6A",
+".i c None",
+".p c #242F6F",
+".a c #4A647D",
+".s c #4DF80B",
+".d c #232D6E",
+".f c #4CF80A",
+".g c #4CF60A",
+".h c #334077",
+".j c #556795",
+".k c #1E2969",
+".l c #2D397B",
+".z c #4E5E98",
+".x c #5DB950",
+".c c #38447F",
+".v c #242F72",
+".b c #34427B",
+".n c #43528D",
+".m c #1E296C",
+".M c #1D276B",
+".N c #60EB2E",
+".B c #404E8A",
+".V c #2C377D",
+".C c #47EE08",
+".Z c #5CF620",
+".A c #1D2661",
+".S c #4C5C99",
+".D c #485895",
+".F c #28346F",
+".G c #475694",
+".H c #364480",
+".J c #48598B",
+".K c #43954A",
+".L c #33407D",
+".P c #222C69",
+".I c #303C7A",
+".U c #808CAE",
+".Y c #2E3A78",
+".T c #2B3875",
+".R c #45E609",
+".E c #2B3675",
+".W c #53FD10",
+".Q c #44BF26",
+".! c #465296",
+".~ c #25306F",
+".^ c #757EA3",
+"./ c #496C71",
+".( c #42587E",
+".) c #2E3A7B",
+"._ c #2D387A",
+".` c #48E40F",
+".' c #3C468C",
+".] c #1B2465",
+".[ c #4A5B93",
+".{ c #46C821",
+".} c #273274",
+".| c #232E70",
+"X c #171F57",
+"X. c #46558F",
+"XX c #458D52",
+"Xo c #222C6F",
+"XO c #212C6E",
+"X+ c #52CE30",
+"X@ c #313C81",
+"X# c #43538C",
+"X$ c #6C9F7F",
+"X% c #48F108",
+"X& c #1C2669",
+"X* c #47EF07",
+"X= c #4F5F9B",
+"X- c #3F4D88",
+"X; c #4B5B97",
+"X: c #44DE0E",
+"X> c #273277",
+"X, c #495995",
+"X< c #253075",
+"X1 c #475793",
+"X2 c #384A77",
+"X3 c #465592",
+"X4 c #36417F",
+"X5 c #5663A5",
+"X6 c #212C71",
+"X7 c #4CE019",
+"X8 c #41765B",
+"X9 c #405282",
+"X0 c #41626F",
+"Xq c #45E708",
+"Xw c #394785",
+"Xe c #439D42",
+"Xr c #596D97",
+"Xt c #545FA6",
+"Xy c #334475",
+"Xu c #334275",
+"Xi c #427F55",
+"Xp c #394588",
+"Xa c #263172",
+"Xs c #38467D",
+"Xd c #354184",
+"Xf c #343F83",
+"Xg c #333F82",
+"Xh c #202B6C",
+"Xj c #49F408",
+"Xk c #1F296B",
+"Xl c #49F208",
+"Xz c #567E79",
+"Xx c #2F4074",
+"Xc c #51609C",
+"Xv c #1D2769",
+"Xb c #48F007",
+"Xn c #4A5A95",
+"Xm c #4C7D65",
+"XM c #475692",
+"XN c #232D72",
+"XB c #212B70",
+"XV c #1F296E",
+"XC c #1E296D",
+"XZ c #2D3A75",
+"XA c #48DD14",
+"XS c #3E517F",
+/* pixels */
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iXa.; H H H K L s.<.2 V b.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.E fXpXdXf 6.V G HX>X< LXN.<X6 U.2XV.A y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i O ; >.'XpXdXf 6.V G HX>X< LXN.<X6 U.2.2XVXV 8 y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iX4.w.w ( ; >.'XpXdX@ 6.V G HX>X< LXN.<X6 U.2.2XVXC 8 8 8X& y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iX5X5.w (.! ; >.'XpXfX@ 6.V G HX>X< LXN.<XB U.2.3XVXC 8 8 8.5.M.#.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i r ^ ^Xt.w (.! ; >.'XpXfX@ 6.V G H KX< LXN.<XB U.2XVXVXC 8 8 8.M.M.MX& y.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i g g ^.:Xt.w (.! ; >.' %XfX@ 6.V G H KX< LXN.<XB.2.2XVXVXC 8 8 8.M.M.M A A ,.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i B g g g ^X5Xt.w (.! ; >Xp %XfX@ 6.V G H.>X< s IX6XB.2.2XVXV 8 8 8.5.M.M A A A A.#X .i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.[ g g g ^.:Xt.w (.! ; >.'XpXd - 6.V G HX>.> L s IX6XB.2.3XVXC 8 8 8.M.M.M A A AXvX& ,X .i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.* g g g g ^X5Xt.w (.! ; >.'Xp a.-.q.V G HX>X< LXN.<XB U.2.3XVXC 8 8 8.M.M.M A A AXvX&X& ,X .i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.[ g g g g ^.:Xt.w (.! ; >.'Xp 1X0...( f.& H KX< LXN.<XB.2.2XVXVXC 8 8.M.M.M A A AXvX&X&X&.# ,X .i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i B g g g g ^.:XtXt.w C r ; >.' a / _.x..Xs nX>.>X< s IX6XB.2.3XVXV 8 8 8 8 8.M.M A A AXvXvX&.#.# ,X .i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i g g g g ^.:X5X5X5.r.6Xr P.'Xp.H 3 _.x...b [X>X< LXN.<X6 U.2.3XVXVXCXC 8.m.m.m 8 8 8 8.+ AXvXv.#.# ,.i.i.i.i.i.i.i",
+".i.i.i.i.i.i g g g g ^ ^.:.:.:X5.6X$.6., OXp.q 3XXX+Xm.b @ KX<.vXN.<XB U.2.2.2.2.2.2.2.2.2 5 5 5 : 5.mXk 8.+.+XvXv.].i.i.i.i.i.i",
+".i.i.i.i.i r g g ^ ^.:.: h.6.rXr.6 ..6X. OXdXs uXXX+Xm.b {.> L sXN.<XBXBXBXBXBXBXBXBXoXoXoXoXoXOXOXOXhXh : :XkXk.+.+ y.i.i.i.i.i",
+".i.i.i.i.i ^ ^ ^.:X5Xt.:.^X$.6XrX$ ..6.J.8Xd /.u.KX+Xm.h $X< L sXNXN.<.<.<XNXN.|.|.|.|.|.|.|.|.|.|.dXo.dXoXOXhXh : : ].i.i.i.i.i",
+".i.i.i.iX5 ^.U.UXtXt.w.:.6 .X$XrX$ . lX9 1 x.a.K.tX+Xm.h $ L L.v.v.v.v.v.v.v.v.v.v.v.v.v.v } }.v.v.v.v.p.|.|.d.dXOXh : ].i.i.i.i",
+".i.i.iX4X5Xt.U.U.w.w (X5.6 .X$XrX$ . W.( /.-XzX+X+ mXm.h $X< L LX<X<X<X<X<.>.>.>.>.>.>.>.}.}.}XaXaXaXa } } }.p.p.|.dXOXh.A.i.i.i",
+".i.i.i.w.w.w.w.w ( (.GXc.6 . .X$ . . W 3 /X9 l m m m _Xy J.>.>.>.>.>.>.}.} {.} [.;.;.;.;.; [ [ [ [ {.}.}.}XaXa } }.p.d.d :.i.i.i",
+".i.i.i.w ( ( ( (.!.! d.z.6 . ..N.N mXX 3 3.( l m m mXi RXx {.}.;X>X>.;.&.Y 7.Y n.&.&.&.&.&.&.&.& [ [ [ [ { {.} $Xa } }.p.d.i.i.i",
+".i.i O ( %.!.U.U ; ; d.zX$ ..N.N.N mXe.uX8 l.x.Z.Z ` =Xi.u R J H [ + Q.IX2X0 3.I n n n n n n n n n n n n + [ [ { { $Xa }.~.A.i.i",
+".i.i ; ;Xf ;.U.U > >XM.jX$.N.N k.Z.N.tX8.tX+ m 2 2 2X7 < j RXx n.Y f.h.bX0.K./.b Q.l.l.l.l.l.l.l.l._._ n n n n + [ @ { $Xa.~.i.i",
+".i.E > >X@ >.U.U.' '.j.6.x.N.Z k.Z.ZX+ =X+ m `.W.W | `X7 c j.u.h 3./.(X2./ _X0Xs.h.Y o.) v v v v.).) o.l o._ n n.E + @ @ $ $.P.i",
+".i f.'.'.).'.U.UXp BXz . m.Z k k k k.Z ` 2 2.W.W # #.X.g.$ w _ /.. W..XS./XmX0XsX2Xy.b X v v v v v v v v.) o o o n n.E + @ {.P.i",
+".iXpXpXpXpXp % % )X#Xz ..N k k k k k 2 2 2.W # # # &.X.gX7 < _.(Xm.t _./..Xm./XSX0X8 u.H.b f f - - - - v v v.).I o.Y Q.T.E @ $.i",
+".iXdXdXdXfXfXfXf 1. l m.Z k k k z z z z.W.W # # & &.X.gX7.$ WX0 _ w WXmXmXm./.(...t.. /.-.-.HXg.q.q - - - f X v.) o o.Y Q.E @.i",
+"XaXfXfX@.;X@.^.U.a l.x.N.Z k k z z z z.W.W # & &.X.X.g.o `X7 w W.t w W.. _ W...(Xm = _X0X0./.( a.q.H.q.q.q -.L f X.I.I o.Y Q.T.F",
+".; 6 6 6.} 6.^.UXz . m k k z z z z.W.W.W # # &.X.s.g.o.o.@.@X7.$.$ < W.a _ w _.( _ w.KX8XX.t.. /.H x xXd.H.q.q.q.L f X.I o.Y Q +",
+" H.V.V.V.v.V.^.U lX+ m z z z z.W.W.W # # & &.X.s.g.o.o NXl.@.`.`XAX7 w W.t <XX./.K.{ c = c wXX uX2XsXsXs.bXs.b.b.h f f X.I o.Y.T",
+" H G G.v.| G.^.U l m.Z z.W.W.W.W # # # & *.X.s.g.o.o N NXlXlX%X%.C qXA.$.=.= =X8 =.=.y.y.y.=Xe.9X0 u u uXSXS / 3 /XsXs f X.I o Q",
+" H H H H [XZ.u _.x.Z 2.W.W # # # # & *.X.s.s.g.o.o N NXl.@X%XbX* 0 q.`.`XAX:.Q =.QX:X:X:X: i.QXeXe.K.K.KXX _XXXXXi..X0Xs f X.I.Y",
+" KX>X>.^.^ R jX+X7 2.W # # # & & * *.X.s.g.g.o.o N NXlXlX%X%X*X* F F 0 0 q ~ MX7.`XqXq ~.R.RX:X7X7.= p.$.$ <.$ p.QX+X$.^.^ f X o",
+" LX<X<.^ h R jX+X7 2 | # & & * *.X.s.g.g.o.o N NXlXl.@X%XbX*X* F F 0 0 q q ~ MX7.`XqXq ~.R.R.`X7X7.= p.$.$ <.$ p.QX+X$.^.^.q f.I",
+" s L L L.~ R j <X7 | | & * *.X.X.f.g.o.o.O NXlXlXlXlX%X%X*X* F F 0 0 q q ~ ~ M.yX:.RXq ~.R.R i.y.=.= p p p.{.{ p.Q c j 3.b.q.L X",
+".<XNXNXN.| J.6X$.t ` `.X.X.s.f.g.o.o.O.O NXlXl ZX%X%XbX*X* F F 0 q ~.`XAX:X:.Q =.Q i iX: i i.QXeXe.K.K.K jXi j.K _X8.uXx.TX4.q f",
+".2.<.<.<.<XN.^.^Xi.$ `.f.g.g.o.o.O.O N NXlXlX%X%X%X%X*X* F F 0 0 ~.RXA.$.=.= =Xm =.=.=.y.= pXe././.a.a.(. . .(.(.(X9 1.- a.H.q f",
+" VX6X6X6XBXB h.^X8 <X7.o.o.o.O.O NXjXlXlXlX%X%XbX*X*X* F q !.`XAXA.y w W.t < W./ W.{ c = c w _. . X# B B D DX9 1 1 1 e.- a a.H.L",
+" b U U U U U h.^.9 w.$ N N.O N NXlXlXlXlX%X%XbXbX*X* F F ! ~XA.$.$ < W.a l w l.a l w.KXm W.tXz.[ 4X3 P d d Y.4 9 E E.8 e.- a.H.L",
+".i.2.2.2.2.2Xh } 3X8.tX7 `XjXlXlXl ZX%X%XbX*X*X* F F.7 qXA.= w W.t w WXz l WXz.a l.t l.aXzXz.j.[X3.GX1X3 P.1.n.4 9 EX- e e a a.i",
+".iXV.2.2.3XVXV.2 JXyXi.$X7XlXlXlX%X%XbXbX*X* F F F F ! ~.=.Q W.a l w W l l lXz.jXz.tXz.[.[.[XnX,.D.D.D.GX3 P.1.n B.BX-.8 e.-.c.i",
+".i.AXVXVXVXV h h.d JX8 <.$.CX*X%X* F !.R ~ q.7 0 0 q.RX: c.K... Xm.t lXzXz lXz.[.aXm.a.*.[.[Xn tX;X;X,.DX1X3 P.1.4 9 EX- e e.h.i",
+".i yXVXCXCXC h h : .9 w <.C.CXb F 0 MX: M q q 0 q q M.yXe.u.(X9./ WXz. Xz l.a.[.[. .[X; t.S.S.S.S.*X;Xn.DX1X3 4.n B.BX-.8 e.h.i",
+".i.i 8 8 8 8 h hXk.P RX8.tXA.`X* ~ M.{ =.Q.=X: ~ ~ ~.y.{.K uX9 D. ./.a. ./ WXz.[.[.[Xn.0.SX=X=X=X=.S.SX;Xn.,XM P.1.4 9X-.8.-.i.i",
+".i.i y 8 8 8 h h 8 b J RXi.$XAX* M.y =X8Xe.Q.=.R.R.R.=.Q j.(X- E.B BX#X#./ WXz.z.,.0.S.SX=X=X=X=X=X=.S.SX;.D.,X3.1.n 9X-X-.b.i.i",
+".i.i.i 8 8 8 8.5.M A.P JXi.{.$.`.y.=Xe.uX8Xi =XAXAXA = _.9 / e.e EX- BX.. Xz.j.[X,.0.SX=X= S C C C SX=.%X;Xn.,XM 4.n B.BX-.i.i.i",
+".i.i.iX&.5.M.M.M.M.M ] JX8 <.{.$.= p j R R 3XX.{.{.{ _.(XS e O E E ' Y dXM.[.[X, t.SX=X= S C C C C CX=X=.SXn.DXM 4.n B.B 1.i.i.i",
+".i.i.i y.M.M h h.M , ] JX8 w =XX =.{ j R RX2 _.{.{.{ _X9XsXw O E E T Y Y.1 4XM.D t.SX=X= C C C C C C SX=.SXn.DXM 4.n B.BXs.i.i.i",
+".i.i.i.i.#.M h h A , ] J.9 cXi.uXi c j R RXy _ < < <Xm 1.cXw O E E ' Y d PX3.DX, t.SX=X= C C CX5 C C SX=.SXn.DXM 4.n BX-.i.i.i.i",
+".i.i.i.i.iX& A A A A ].F.9XeX8 3Xi cX8 RXyXyX8.Q.Q <Xm 1.cXw O.e E ' T d dX3X1.DX;.SX=X= C C C C C CX=.z.*Xn.,XM 4.n D.i.i.i.i.i",
+".i.i.i.i.i y A A A A ].F.u.K.9 RX8 =.9XuXyXyX8 c.Q <Xm 1.cXw O.e E 9 T Y dX3.G.DX;.*.SX= S C C C C SX=.%X;Xn.,X3 4.nXs.i.i.i.i.i",
+".i.i.i.i.i.i , AXvXv ].P R.u 3Xx.9Xe.9.h.h 7.u j =.QXm 1.c ) O.e E E T Y d PX1.DX,X;.S.SX=X= S SX=X=.z.*Xn.DXMX..1 D.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.#X&X&.#.+.P J J.u.KX0.hXZ QXy.u j c.. 1.c )Xw O E E 9 T.1 dX3.G.DXnX;.S.%X=X=X=.z.%.*XnXn.,X3 4 B.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.iX ,X&X&.#Xv.k.P R.uX2XZ.E nXx u j =.. 1.H )Xw e.e E E T.4 d PX3X1.DXnX;X;.S.S.S.*X;XnXn.,XM 4.nXs.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.iX ,.#.#Xv.+ :.d.F.T @ @ @ nXZ RX8Xe./.-.H a ) e O.8 E 9 T Y.1 PX3X1.,.DXnXnXnXnXnXn.D.,XMX..nXs.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.iX ,.#.#.+XkXh.d.~ } $ [ n.TXx.u.9.(.c.q x )Xw O.8 E E 9.4.n.1 PX3XM.,.,.D.D.D.,.,XMX3 4.nXs.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.iX ,.#XvXkXh.d.p } $ { +.T.Y.h.b.b.q.q x a )Xw e.8 E E 9.4.n.1 4 PX3XMXMXMXMXMX3X. 4.nXs.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.iX ,Xv.+ :XO.| }Xa { [.E n.Y.Y.I f.q.q x a ) e e.8 E E 9 B.4.n.1.1 4 4 4 4 4 4.1 BXs.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.].+ :Xh.d.p } $ @ + n.Y o.I f.L.q.H a aXw e e.8 E E.B 9 B.4.n.n.n.n.n.n.n D.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i y ] :XO.d }Xa { @.E Q o.I X f.L.q.H a aXw e e.8X-X- E.B 9 9 B B B B DXs.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i ]Xh.d.p } $ @ +.T.Y o.I X f.L.q.H a aXw e e e.8X-X-X-X-.B.B.BX-.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.A :.d.~Xa $ @.E Q.Y o.I X f.L.q.H a a a.- e e e.8.8X-X- 1Xs.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.A.~ $ { @.E Q.Y o.I X f.q.qX4.H a a a.- e e.-.b.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.P.P $ @.T Q.Y o.I X f.L.q.q.H.H a.c.h.h.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.F +.T Q.Y o.I X f f.L.L.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i"
+};
diff --git a/arts/builder/pics/Synth_PLAY_AKAIS.xpm b/arts/builder/pics/Synth_PLAY_AKAIS.xpm
new file mode 100644
index 00000000..a7cedce2
--- /dev/null
+++ b/arts/builder/pics/Synth_PLAY_AKAIS.xpm
@@ -0,0 +1,317 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 246 2",
+/* colors */
+" c #27326F",
+" . c #68D14E",
+" X c #303E7B",
+" o c #2E3A79",
+" O c #3B4889",
+" + c #2A3675",
+" @ c #293474",
+" # c #51FD0F",
+" $ c #273272",
+" % c #374285",
+" & c #4FFB0D",
+" * c #4EFB0C",
+" = c #44A73B",
+" - c #323E80",
+" ; c #434E94",
+" : c #202A6B",
+" > c #3E4A8F",
+" , c #1C2667",
+" < c #4BCA27",
+" 1 c #3D4B84",
+" 2 c #52F913",
+" 3 c #375074",
+" 4 c #45538F",
+" 5 c #1F2A6D",
+" 6 c #2F3A80",
+" 7 c #323D79",
+" 8 c #1E286C",
+" 9 c #414F8B",
+" 0 c #46ED07",
+" q c #46EB07",
+" w c #4CB935",
+" e c #3B4985",
+" r c #4C5999",
+" t c #4B5998",
+" y c #1A235E",
+" u c #3A5970",
+" i c #43DC0E",
+" p c #44CF19",
+" a c #384582",
+" s c #232E74",
+" d c #445191",
+" f c #323F7C",
+" g c #656FB8",
+" h c #6F76A4",
+" j c #408551",
+" k c #5CFE19",
+" l c #538967",
+" z c #56FE13",
+" x c #374384",
+" c c #46B332",
+" v c #303B7D",
+" b c #1D2767",
+" n c #2B3778",
+" m c #5BE22F",
+" M c #44E30B",
+" N c #4AF40A",
+" B c #42508B",
+" V c #1E296B",
+" C c #51629D",
+" Z c #48F208",
+" A c #1D276A",
+" S c #50609C",
+" D c #404E89",
+" F c #47EE07",
+" G c #2A357A",
+" H c #283378",
+" J c #29366F",
+" K c #263176",
+" L c #242F74",
+" P c #465492",
+" I c #222D72",
+" U c #202B70",
+" Y c #43508F",
+" T c #41508D",
+" R c #30496F",
+" E c #3E4C8A",
+" W c #52955B",
+" Q c #2D3876",
+" ! c #45EA08",
+" ~ c #45E808",
+" ^ c #5D68AF",
+" / c #3C4F7E",
+" ( c #4C569B",
+" ) c #394685",
+" _ c #4B845E",
+" ` c #4EEC14",
+" ' c #404E8F",
+" ] c #1E2867",
+" [ c #293475",
+" { c #283474",
+" } c #253071",
+" | c #4FF90E",
+". c #475E85",
+".. c #4A756A",
+".X c #4DF90C",
+".o c #4BF50A",
+".O c #4AF509",
+".+ c #1E286A",
+".@ c #49F108",
+".# c #1C2668",
+".$ c #4BD51E",
+".% c #4D5D98",
+".& c #293478",
+".* c #4C5B97",
+".= c #45D318",
+".- c #3B4783",
+".; c #273276",
+".: c #5B67A9",
+".> c #263075",
+"., c #485793",
+".< c #222C71",
+".1 c #44538F",
+".2 c #202A6F",
+".3 c #1F2A6E",
+".4 c #42518D",
+".5 c #1D286C",
+".6 c #699088",
+".7 c #45ED07",
+".8 c #3D4B88",
+".9 c #406B63",
+".0 c #4B5B99",
+".q c #34417F",
+".w c #505BA1",
+".e c #3C498A",
+".r c #6175A1",
+".t c #4EA645",
+".y c #45D814",
+".u c #3A5E6A",
+".i c None",
+".p c #242F6F",
+".a c #4A647D",
+".s c #4DF80B",
+".d c #232D6E",
+".f c #4CF80A",
+".g c #4CF60A",
+".h c #334077",
+".j c #556795",
+".k c #1E2969",
+".l c #2D397B",
+".z c #4E5E98",
+".x c #5DB950",
+".c c #38447F",
+".v c #242F72",
+".b c #34427B",
+".n c #43528D",
+".m c #1E296C",
+".M c #1D276B",
+".N c #60EB2E",
+".B c #404E8A",
+".V c #2C377D",
+".C c #47EE08",
+".Z c #5CF620",
+".A c #1D2661",
+".S c #4C5C99",
+".D c #485895",
+".F c #28346F",
+".G c #475694",
+".H c #364480",
+".J c #48598B",
+".K c #43954A",
+".L c #33407D",
+".P c #222C69",
+".I c #303C7A",
+".U c #808CAE",
+".Y c #2E3A78",
+".T c #2B3875",
+".R c #45E609",
+".E c #2B3675",
+".W c #53FD10",
+".Q c #44BF26",
+".! c #465296",
+".~ c #25306F",
+".^ c #757EA3",
+"./ c #496C71",
+".( c #42587E",
+".) c #2E3A7B",
+"._ c #2D387A",
+".` c #48E40F",
+".' c #3C468C",
+".] c #1B2465",
+".[ c #4A5B93",
+".{ c #46C821",
+".} c #273274",
+".| c #232E70",
+"X c #171F57",
+"X. c #46558F",
+"XX c #458D52",
+"Xo c #222C6F",
+"XO c #212C6E",
+"X+ c #52CE30",
+"X@ c #313C81",
+"X# c #43538C",
+"X$ c #6C9F7F",
+"X% c #48F108",
+"X& c #1C2669",
+"X* c #47EF07",
+"X= c #4F5F9B",
+"X- c #3F4D88",
+"X; c #4B5B97",
+"X: c #44DE0E",
+"X> c #273277",
+"X, c #495995",
+"X< c #253075",
+"X1 c #475793",
+"X2 c #384A77",
+"X3 c #465592",
+"X4 c #36417F",
+"X5 c #5663A5",
+"X6 c #212C71",
+"X7 c #4CE019",
+"X8 c #41765B",
+"X9 c #405282",
+"X0 c #41626F",
+"Xq c #45E708",
+"Xw c #394785",
+"Xe c #439D42",
+"Xr c #596D97",
+"Xt c #545FA6",
+"Xy c #334475",
+"Xu c #334275",
+"Xi c #427F55",
+"Xp c #394588",
+"Xa c #263172",
+"Xs c #38467D",
+"Xd c #354184",
+"Xf c #343F83",
+"Xg c #333F82",
+"Xh c #202B6C",
+"Xj c #49F408",
+"Xk c #1F296B",
+"Xl c #49F208",
+"Xz c #567E79",
+"Xx c #2F4074",
+"Xc c #51609C",
+"Xv c #1D2769",
+"Xb c #48F007",
+"Xn c #4A5A95",
+"Xm c #4C7D65",
+"XM c #475692",
+"XN c #232D72",
+"XB c #212B70",
+"XV c #1F296E",
+"XC c #1E296D",
+"XZ c #2D3A75",
+"XA c #48DD14",
+"XS c #3E517F",
+/* pixels */
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iXa.; H H H K L s.<.2 V b.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.E fXpXdXf 6.V G HX>X< LXN.<X6 U.2XV.A y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i O ; >.'XpXdXf 6.V G HX>X< LXN.<X6 U.2.2XVXV 8 y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iX4.w.w ( ; >.'XpXdX@ 6.V G HX>X< LXN.<X6 U.2.2XVXC 8 8 8X& y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iX5X5.w (.! ; >.'XpXfX@ 6.V G HX>X< LXN.<XB U.2.3XVXC 8 8 8.5.M.#.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i r ^ ^Xt.w (.! ; >.'XpXfX@ 6.V G H KX< LXN.<XB U.2XVXVXC 8 8 8.M.M.MX& y.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i g g ^.:Xt.w (.! ; >.' %XfX@ 6.V G H KX< LXN.<XB.2.2XVXVXC 8 8 8.M.M.M A A ,.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i B g g g ^X5Xt.w (.! ; >Xp %XfX@ 6.V G H.>X< s IX6XB.2.2XVXV 8 8 8.5.M.M A A A A.#X .i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.[ g g g ^.:Xt.w (.! ; >.'XpXd - 6.V G HX>.> L s IX6XB.2.3XVXC 8 8 8.M.M.M A A AXvX& ,X .i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.* g g g g ^X5Xt.w (.! ; >.'Xp a.-.q.V G HX>X< LXN.<XB U.2.3XVXC 8 8 8.M.M.M A A AXvX&X& ,X .i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.[ g g g g ^.:Xt.w (.! ; >.'Xp 1X0...( f.& H KX< LXN.<XB.2.2XVXVXC 8 8.M.M.M A A AXvX&X&X&.# ,X .i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i B g g g g ^.:XtXt.w C r ; >.' a / _.x..Xs nX>.>X< s IX6XB.2.3XVXV 8 8 8 8 8.M.M A A AXvXvX&.#.# ,X .i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i g g g g ^.:X5X5X5.r.6Xr P.'Xp.H 3 _.x...b [X>X< LXN.<X6 U.2.3XVXVXCXC 8.m.m.m 8 8 8 8.+ AXvXv.#.# ,.i.i.i.i.i.i.i",
+".i.i.i.i.i.i g g g g ^ ^.:.:.:X5.6X$.6., OXp.q 3XXX+Xm.b @ KX<.vXN.<XB U.2.2.2.2.2.2.2.2.2 5 5 5 : 5.mXk 8.+.+XvXv.].i.i.i.i.i.i",
+".i.i.i.i.i r g g ^ ^.:.: h.6.rXr.6 ..6X. OXdXs uXXX+Xm.b {.> L sXN.<XBXBXBXBXBXBXBXBXoXoXoXoXoXOXOXOXhXh : :XkXk.+.+ y.i.i.i.i.i",
+".i.i.i.i.i ^ ^ ^.:X5Xt.:.^X$.6XrX$ ..6.J.8Xd /.u.KX+Xm.h $X< L sXNXN.<.<.<XNXN.|.|.|.|.|.|.|.|.|.|.dXo.dXoXOXhXh : : ].i.i.i.i.i",
+".i.i.i.iX5 ^.U.UXtXt.w.:.6 .X$XrX$ . lX9 1 x.a.K.tX+Xm.h $ L L.v.v.v.v.v.v.v.v.v.v.v.v.v.v } }.v.v.v.v.p.|.|.d.dXOXh : ].i.i.i.i",
+".i.i.iX4X5Xt.U.U.w.w (X5.6 .X$XrX$ . W.( /.-XzX+X+ mXm.h $X< L LX<X<X<X<X<.>.>.>.>.>.>.>.}.}.}XaXaXaXa } } }.p.p.|.dXOXh.A.i.i.i",
+".i.i.i.w.w.w.w.w ( (.GXc.6 . .X$ . . W 3 /X9 l m m m _Xy J.>.>.>.>.>.>.}.} {.} [.;.;.;.;.; [ [ [ [ {.}.}.}XaXa } }.p.d.d :.i.i.i",
+".i.i.i.w ( ( ( (.!.! d.z.6 . ..N.N mXX 3 3.( l m m mXi RXx {.}.;X>X>.;.&.Y 7.Y n.&.&.&.&.&.&.&.& [ [ [ [ { {.} $Xa } }.p.d.i.i.i",
+".i.i O ( %.!.U.U ; ; d.zX$ ..N.N.N mXe.uX8 l.x.Z.Z ` =Xi.u R J H [ + Q.IX2X0 3.I n n n n n n n n n n n n + [ [ { { $Xa }.~.A.i.i",
+".i.i ; ;Xf ;.U.U > >XM.jX$.N.N k.Z.N.tX8.tX+ m 2 2 2X7 < j RXx n.Y f.h.bX0.K./.b Q.l.l.l.l.l.l.l.l._._ n n n n + [ @ { $Xa.~.i.i",
+".i.E > >X@ >.U.U.' '.j.6.x.N.Z k.Z.ZX+ =X+ m `.W.W | `X7 c j.u.h 3./.(X2./ _X0Xs.h.Y o.) v v v v.).) o.l o._ n n.E + @ @ $ $.P.i",
+".i f.'.'.).'.U.UXp BXz . m.Z k k k k.Z ` 2 2.W.W # #.X.g.$ w _ /.. W..XS./XmX0XsX2Xy.b X v v v v v v v v.) o o o n n.E + @ {.P.i",
+".iXpXpXpXpXp % % )X#Xz ..N k k k k k 2 2 2.W # # # &.X.gX7 < _.(Xm.t _./..Xm./XSX0X8 u.H.b f f - - - - v v v.).I o.Y Q.T.E @ $.i",
+".iXdXdXdXfXfXfXf 1. l m.Z k k k z z z z.W.W # # & &.X.gX7.$ WX0 _ w WXmXmXm./.(...t.. /.-.-.HXg.q.q - - - f X v.) o o.Y Q.E @.i",
+"XaXfXfX@.;X@.^.U.a l.x.N.Z k k z z z z.W.W # & &.X.X.g.o `X7 w W.t w W.. _ W...(Xm = _X0X0./.( a.q.H.q.q.q -.L f X.I.I o.Y Q.T.F",
+".; 6 6 6.} 6.^.UXz . m k k z z z z.W.W.W # # &.X.s.g.o.o.@.@X7.$.$ < W.a _ w _.( _ w.KX8XX.t.. /.H x xXd.H.q.q.q.L f X.I o.Y Q +",
+" H.V.V.V.v.V.^.U lX+ m z z z z.W.W.W # # & &.X.s.g.o.o NXl.@.`.`XAX7 w W.t <XX./.K.{ c = c wXX uX2XsXsXs.bXs.b.b.h f f X.I o.Y.T",
+" H G G.v.| G.^.U l m.Z z.W.W.W.W # # # & *.X.s.g.o.o N NXlXlX%X%.C qXA.$.=.= =X8 =.=.y.y.y.=Xe.9X0 u u uXSXS / 3 /XsXs f X.I o Q",
+" H H H H [XZ.u _.x.Z 2.W.W # # # # & *.X.s.s.g.o.o N NXl.@X%XbX* 0 q.`.`XAX:.Q =.QX:X:X:X: i.QXeXe.K.K.KXX _XXXXXi..X0Xs f X.I.Y",
+" KX>X>.^.^ R jX+X7 2.W # # # & & * *.X.s.g.g.o.o N NXlXlX%X%X*X* F F 0 0 q ~ MX7.`XqXq ~.R.RX:X7X7.= p.$.$ <.$ p.QX+X$.^.^ f X o",
+" LX<X<.^ h R jX+X7 2 | # & & * *.X.s.g.g.o.o N NXlXl.@X%XbX*X* F F 0 0 q q ~ MX7.`XqXq ~.R.R.`X7X7.= p.$.$ <.$ p.QX+X$.^.^.q f.I",
+" s L L L.~ R j <X7 | | & * *.X.X.f.g.o.o.O NXlXlXlXlX%X%X*X* F F 0 0 q q ~ ~ M.yX:.RXq ~.R.R i.y.=.= p p p.{.{ p.Q c j 3.b.q.L X",
+".<XNXNXN.| J.6X$.t ` `.X.X.s.f.g.o.o.O.O NXlXl ZX%X%XbX*X* F F 0 q ~.`XAX:X:.Q =.Q i iX: i i.QXeXe.K.K.K jXi j.K _X8.uXx.TX4.q f",
+".2.<.<.<.<XN.^.^Xi.$ `.f.g.g.o.o.O.O N NXlXlX%X%X%X%X*X* F F 0 0 ~.RXA.$.=.= =Xm =.=.=.y.= pXe././.a.a.(. . .(.(.(X9 1.- a.H.q f",
+" VX6X6X6XBXB h.^X8 <X7.o.o.o.O.O NXjXlXlXlX%X%XbX*X*X* F q !.`XAXA.y w W.t < W./ W.{ c = c w _. . X# B B D DX9 1 1 1 e.- a a.H.L",
+" b U U U U U h.^.9 w.$ N N.O N NXlXlXlXlX%X%XbXbX*X* F F ! ~XA.$.$ < W.a l w l.a l w.KXm W.tXz.[ 4X3 P d d Y.4 9 E E.8 e.- a.H.L",
+".i.2.2.2.2.2Xh } 3X8.tX7 `XjXlXlXl ZX%X%XbX*X*X* F F.7 qXA.= w W.t w WXz l WXz.a l.t l.aXzXz.j.[X3.GX1X3 P.1.n.4 9 EX- e e a a.i",
+".iXV.2.2.3XVXV.2 JXyXi.$X7XlXlXlX%X%XbXbX*X* F F F F ! ~.=.Q W.a l w W l l lXz.jXz.tXz.[.[.[XnX,.D.D.D.GX3 P.1.n B.BX-.8 e.-.c.i",
+".i.AXVXVXVXV h h.d JX8 <.$.CX*X%X* F !.R ~ q.7 0 0 q.RX: c.K... Xm.t lXzXz lXz.[.aXm.a.*.[.[Xn tX;X;X,.DX1X3 P.1.4 9 EX- e e.h.i",
+".i yXVXCXCXC h h : .9 w <.C.CXb F 0 MX: M q q 0 q q M.yXe.u.(X9./ WXz. Xz l.a.[.[. .[X; t.S.S.S.S.*X;Xn.DX1X3 4.n B.BX-.8 e.h.i",
+".i.i 8 8 8 8 h hXk.P RX8.tXA.`X* ~ M.{ =.Q.=X: ~ ~ ~.y.{.K uX9 D. ./.a. ./ WXz.[.[.[Xn.0.SX=X=X=X=.S.SX;Xn.,XM P.1.4 9X-.8.-.i.i",
+".i.i y 8 8 8 h h 8 b J RXi.$XAX* M.y =X8Xe.Q.=.R.R.R.=.Q j.(X- E.B BX#X#./ WXz.z.,.0.S.SX=X=X=X=X=X=.S.SX;.D.,X3.1.n 9X-X-.b.i.i",
+".i.i.i 8 8 8 8.5.M A.P JXi.{.$.`.y.=Xe.uX8Xi =XAXAXA = _.9 / e.e EX- BX.. Xz.j.[X,.0.SX=X= S C C C SX=.%X;Xn.,XM 4.n B.BX-.i.i.i",
+".i.i.iX&.5.M.M.M.M.M ] JX8 <.{.$.= p j R R 3XX.{.{.{ _.(XS e O E E ' Y dXM.[.[X, t.SX=X= S C C C C CX=X=.SXn.DXM 4.n B.B 1.i.i.i",
+".i.i.i y.M.M h h.M , ] JX8 w =XX =.{ j R RX2 _.{.{.{ _X9XsXw O E E T Y Y.1 4XM.D t.SX=X= C C C C C C SX=.SXn.DXM 4.n B.BXs.i.i.i",
+".i.i.i.i.#.M h h A , ] J.9 cXi.uXi c j R RXy _ < < <Xm 1.cXw O E E ' Y d PX3.DX, t.SX=X= C C CX5 C C SX=.SXn.DXM 4.n BX-.i.i.i.i",
+".i.i.i.i.iX& A A A A ].F.9XeX8 3Xi cX8 RXyXyX8.Q.Q <Xm 1.cXw O.e E ' T d dX3X1.DX;.SX=X= C C C C C CX=.z.*Xn.,XM 4.n D.i.i.i.i.i",
+".i.i.i.i.i y A A A A ].F.u.K.9 RX8 =.9XuXyXyX8 c.Q <Xm 1.cXw O.e E 9 T Y dX3.G.DX;.*.SX= S C C C C SX=.%X;Xn.,X3 4.nXs.i.i.i.i.i",
+".i.i.i.i.i.i , AXvXv ].P R.u 3Xx.9Xe.9.h.h 7.u j =.QXm 1.c ) O.e E E T Y d PX1.DX,X;.S.SX=X= S SX=X=.z.*Xn.DXMX..1 D.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.#X&X&.#.+.P J J.u.KX0.hXZ QXy.u j c.. 1.c )Xw O E E 9 T.1 dX3.G.DXnX;.S.%X=X=X=.z.%.*XnXn.,X3 4 B.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.iX ,X&X&.#Xv.k.P R.uX2XZ.E nXx u j =.. 1.H )Xw e.e E E T.4 d PX3X1.DXnX;X;.S.S.S.*X;XnXn.,XM 4.nXs.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.iX ,.#.#Xv.+ :.d.F.T @ @ @ nXZ RX8Xe./.-.H a ) e O.8 E 9 T Y.1 PX3X1.,.DXnXnXnXnXnXn.D.,XMX..nXs.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.iX ,.#.#.+XkXh.d.~ } $ [ n.TXx.u.9.(.c.q x )Xw O.8 E E 9.4.n.1 PX3XM.,.,.D.D.D.,.,XMX3 4.nXs.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.iX ,.#XvXkXh.d.p } $ { +.T.Y.h.b.b.q.q x a )Xw e.8 E E 9.4.n.1 4 PX3XMXMXMXMXMX3X. 4.nXs.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.iX ,Xv.+ :XO.| }Xa { [.E n.Y.Y.I f.q.q x a ) e e.8 E E 9 B.4.n.1.1 4 4 4 4 4 4.1 BXs.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.].+ :Xh.d.p } $ @ + n.Y o.I f.L.q.H a aXw e e.8 E E.B 9 B.4.n.n.n.n.n.n.n D.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i y ] :XO.d }Xa { @.E Q o.I X f.L.q.H a aXw e e.8X-X- E.B 9 9 B B B B DXs.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i ]Xh.d.p } $ @ +.T.Y o.I X f.L.q.H a aXw e e e.8X-X-X-X-.B.B.BX-.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.A :.d.~Xa $ @.E Q.Y o.I X f.L.q.H a a a.- e e e.8.8X-X- 1Xs.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.A.~ $ { @.E Q.Y o.I X f.q.qX4.H a a a.- e e.-.b.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.P.P $ @.T Q.Y o.I X f.L.q.q.H.H a.c.h.h.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.F +.T Q.Y o.I X f f.L.L.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i"
+};
diff --git a/arts/builder/pics/Synth_PLAY_WAV.xpm b/arts/builder/pics/Synth_PLAY_WAV.xpm
new file mode 100644
index 00000000..a7cedce2
--- /dev/null
+++ b/arts/builder/pics/Synth_PLAY_WAV.xpm
@@ -0,0 +1,317 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 246 2",
+/* colors */
+" c #27326F",
+" . c #68D14E",
+" X c #303E7B",
+" o c #2E3A79",
+" O c #3B4889",
+" + c #2A3675",
+" @ c #293474",
+" # c #51FD0F",
+" $ c #273272",
+" % c #374285",
+" & c #4FFB0D",
+" * c #4EFB0C",
+" = c #44A73B",
+" - c #323E80",
+" ; c #434E94",
+" : c #202A6B",
+" > c #3E4A8F",
+" , c #1C2667",
+" < c #4BCA27",
+" 1 c #3D4B84",
+" 2 c #52F913",
+" 3 c #375074",
+" 4 c #45538F",
+" 5 c #1F2A6D",
+" 6 c #2F3A80",
+" 7 c #323D79",
+" 8 c #1E286C",
+" 9 c #414F8B",
+" 0 c #46ED07",
+" q c #46EB07",
+" w c #4CB935",
+" e c #3B4985",
+" r c #4C5999",
+" t c #4B5998",
+" y c #1A235E",
+" u c #3A5970",
+" i c #43DC0E",
+" p c #44CF19",
+" a c #384582",
+" s c #232E74",
+" d c #445191",
+" f c #323F7C",
+" g c #656FB8",
+" h c #6F76A4",
+" j c #408551",
+" k c #5CFE19",
+" l c #538967",
+" z c #56FE13",
+" x c #374384",
+" c c #46B332",
+" v c #303B7D",
+" b c #1D2767",
+" n c #2B3778",
+" m c #5BE22F",
+" M c #44E30B",
+" N c #4AF40A",
+" B c #42508B",
+" V c #1E296B",
+" C c #51629D",
+" Z c #48F208",
+" A c #1D276A",
+" S c #50609C",
+" D c #404E89",
+" F c #47EE07",
+" G c #2A357A",
+" H c #283378",
+" J c #29366F",
+" K c #263176",
+" L c #242F74",
+" P c #465492",
+" I c #222D72",
+" U c #202B70",
+" Y c #43508F",
+" T c #41508D",
+" R c #30496F",
+" E c #3E4C8A",
+" W c #52955B",
+" Q c #2D3876",
+" ! c #45EA08",
+" ~ c #45E808",
+" ^ c #5D68AF",
+" / c #3C4F7E",
+" ( c #4C569B",
+" ) c #394685",
+" _ c #4B845E",
+" ` c #4EEC14",
+" ' c #404E8F",
+" ] c #1E2867",
+" [ c #293475",
+" { c #283474",
+" } c #253071",
+" | c #4FF90E",
+". c #475E85",
+".. c #4A756A",
+".X c #4DF90C",
+".o c #4BF50A",
+".O c #4AF509",
+".+ c #1E286A",
+".@ c #49F108",
+".# c #1C2668",
+".$ c #4BD51E",
+".% c #4D5D98",
+".& c #293478",
+".* c #4C5B97",
+".= c #45D318",
+".- c #3B4783",
+".; c #273276",
+".: c #5B67A9",
+".> c #263075",
+"., c #485793",
+".< c #222C71",
+".1 c #44538F",
+".2 c #202A6F",
+".3 c #1F2A6E",
+".4 c #42518D",
+".5 c #1D286C",
+".6 c #699088",
+".7 c #45ED07",
+".8 c #3D4B88",
+".9 c #406B63",
+".0 c #4B5B99",
+".q c #34417F",
+".w c #505BA1",
+".e c #3C498A",
+".r c #6175A1",
+".t c #4EA645",
+".y c #45D814",
+".u c #3A5E6A",
+".i c None",
+".p c #242F6F",
+".a c #4A647D",
+".s c #4DF80B",
+".d c #232D6E",
+".f c #4CF80A",
+".g c #4CF60A",
+".h c #334077",
+".j c #556795",
+".k c #1E2969",
+".l c #2D397B",
+".z c #4E5E98",
+".x c #5DB950",
+".c c #38447F",
+".v c #242F72",
+".b c #34427B",
+".n c #43528D",
+".m c #1E296C",
+".M c #1D276B",
+".N c #60EB2E",
+".B c #404E8A",
+".V c #2C377D",
+".C c #47EE08",
+".Z c #5CF620",
+".A c #1D2661",
+".S c #4C5C99",
+".D c #485895",
+".F c #28346F",
+".G c #475694",
+".H c #364480",
+".J c #48598B",
+".K c #43954A",
+".L c #33407D",
+".P c #222C69",
+".I c #303C7A",
+".U c #808CAE",
+".Y c #2E3A78",
+".T c #2B3875",
+".R c #45E609",
+".E c #2B3675",
+".W c #53FD10",
+".Q c #44BF26",
+".! c #465296",
+".~ c #25306F",
+".^ c #757EA3",
+"./ c #496C71",
+".( c #42587E",
+".) c #2E3A7B",
+"._ c #2D387A",
+".` c #48E40F",
+".' c #3C468C",
+".] c #1B2465",
+".[ c #4A5B93",
+".{ c #46C821",
+".} c #273274",
+".| c #232E70",
+"X c #171F57",
+"X. c #46558F",
+"XX c #458D52",
+"Xo c #222C6F",
+"XO c #212C6E",
+"X+ c #52CE30",
+"X@ c #313C81",
+"X# c #43538C",
+"X$ c #6C9F7F",
+"X% c #48F108",
+"X& c #1C2669",
+"X* c #47EF07",
+"X= c #4F5F9B",
+"X- c #3F4D88",
+"X; c #4B5B97",
+"X: c #44DE0E",
+"X> c #273277",
+"X, c #495995",
+"X< c #253075",
+"X1 c #475793",
+"X2 c #384A77",
+"X3 c #465592",
+"X4 c #36417F",
+"X5 c #5663A5",
+"X6 c #212C71",
+"X7 c #4CE019",
+"X8 c #41765B",
+"X9 c #405282",
+"X0 c #41626F",
+"Xq c #45E708",
+"Xw c #394785",
+"Xe c #439D42",
+"Xr c #596D97",
+"Xt c #545FA6",
+"Xy c #334475",
+"Xu c #334275",
+"Xi c #427F55",
+"Xp c #394588",
+"Xa c #263172",
+"Xs c #38467D",
+"Xd c #354184",
+"Xf c #343F83",
+"Xg c #333F82",
+"Xh c #202B6C",
+"Xj c #49F408",
+"Xk c #1F296B",
+"Xl c #49F208",
+"Xz c #567E79",
+"Xx c #2F4074",
+"Xc c #51609C",
+"Xv c #1D2769",
+"Xb c #48F007",
+"Xn c #4A5A95",
+"Xm c #4C7D65",
+"XM c #475692",
+"XN c #232D72",
+"XB c #212B70",
+"XV c #1F296E",
+"XC c #1E296D",
+"XZ c #2D3A75",
+"XA c #48DD14",
+"XS c #3E517F",
+/* pixels */
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iXa.; H H H K L s.<.2 V b.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.E fXpXdXf 6.V G HX>X< LXN.<X6 U.2XV.A y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i O ; >.'XpXdXf 6.V G HX>X< LXN.<X6 U.2.2XVXV 8 y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iX4.w.w ( ; >.'XpXdX@ 6.V G HX>X< LXN.<X6 U.2.2XVXC 8 8 8X& y.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.iX5X5.w (.! ; >.'XpXfX@ 6.V G HX>X< LXN.<XB U.2.3XVXC 8 8 8.5.M.#.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i r ^ ^Xt.w (.! ; >.'XpXfX@ 6.V G H KX< LXN.<XB U.2XVXVXC 8 8 8.M.M.MX& y.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i g g ^.:Xt.w (.! ; >.' %XfX@ 6.V G H KX< LXN.<XB.2.2XVXVXC 8 8 8.M.M.M A A ,.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i B g g g ^X5Xt.w (.! ; >Xp %XfX@ 6.V G H.>X< s IX6XB.2.2XVXV 8 8 8.5.M.M A A A A.#X .i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.[ g g g ^.:Xt.w (.! ; >.'XpXd - 6.V G HX>.> L s IX6XB.2.3XVXC 8 8 8.M.M.M A A AXvX& ,X .i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.* g g g g ^X5Xt.w (.! ; >.'Xp a.-.q.V G HX>X< LXN.<XB U.2.3XVXC 8 8 8.M.M.M A A AXvX&X& ,X .i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.[ g g g g ^.:Xt.w (.! ; >.'Xp 1X0...( f.& H KX< LXN.<XB.2.2XVXVXC 8 8.M.M.M A A AXvX&X&X&.# ,X .i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i B g g g g ^.:XtXt.w C r ; >.' a / _.x..Xs nX>.>X< s IX6XB.2.3XVXV 8 8 8 8 8.M.M A A AXvXvX&.#.# ,X .i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i g g g g ^.:X5X5X5.r.6Xr P.'Xp.H 3 _.x...b [X>X< LXN.<X6 U.2.3XVXVXCXC 8.m.m.m 8 8 8 8.+ AXvXv.#.# ,.i.i.i.i.i.i.i",
+".i.i.i.i.i.i g g g g ^ ^.:.:.:X5.6X$.6., OXp.q 3XXX+Xm.b @ KX<.vXN.<XB U.2.2.2.2.2.2.2.2.2 5 5 5 : 5.mXk 8.+.+XvXv.].i.i.i.i.i.i",
+".i.i.i.i.i r g g ^ ^.:.: h.6.rXr.6 ..6X. OXdXs uXXX+Xm.b {.> L sXN.<XBXBXBXBXBXBXBXBXoXoXoXoXoXOXOXOXhXh : :XkXk.+.+ y.i.i.i.i.i",
+".i.i.i.i.i ^ ^ ^.:X5Xt.:.^X$.6XrX$ ..6.J.8Xd /.u.KX+Xm.h $X< L sXNXN.<.<.<XNXN.|.|.|.|.|.|.|.|.|.|.dXo.dXoXOXhXh : : ].i.i.i.i.i",
+".i.i.i.iX5 ^.U.UXtXt.w.:.6 .X$XrX$ . lX9 1 x.a.K.tX+Xm.h $ L L.v.v.v.v.v.v.v.v.v.v.v.v.v.v } }.v.v.v.v.p.|.|.d.dXOXh : ].i.i.i.i",
+".i.i.iX4X5Xt.U.U.w.w (X5.6 .X$XrX$ . W.( /.-XzX+X+ mXm.h $X< L LX<X<X<X<X<.>.>.>.>.>.>.>.}.}.}XaXaXaXa } } }.p.p.|.dXOXh.A.i.i.i",
+".i.i.i.w.w.w.w.w ( (.GXc.6 . .X$ . . W 3 /X9 l m m m _Xy J.>.>.>.>.>.>.}.} {.} [.;.;.;.;.; [ [ [ [ {.}.}.}XaXa } }.p.d.d :.i.i.i",
+".i.i.i.w ( ( ( (.!.! d.z.6 . ..N.N mXX 3 3.( l m m mXi RXx {.}.;X>X>.;.&.Y 7.Y n.&.&.&.&.&.&.&.& [ [ [ [ { {.} $Xa } }.p.d.i.i.i",
+".i.i O ( %.!.U.U ; ; d.zX$ ..N.N.N mXe.uX8 l.x.Z.Z ` =Xi.u R J H [ + Q.IX2X0 3.I n n n n n n n n n n n n + [ [ { { $Xa }.~.A.i.i",
+".i.i ; ;Xf ;.U.U > >XM.jX$.N.N k.Z.N.tX8.tX+ m 2 2 2X7 < j RXx n.Y f.h.bX0.K./.b Q.l.l.l.l.l.l.l.l._._ n n n n + [ @ { $Xa.~.i.i",
+".i.E > >X@ >.U.U.' '.j.6.x.N.Z k.Z.ZX+ =X+ m `.W.W | `X7 c j.u.h 3./.(X2./ _X0Xs.h.Y o.) v v v v.).) o.l o._ n n.E + @ @ $ $.P.i",
+".i f.'.'.).'.U.UXp BXz . m.Z k k k k.Z ` 2 2.W.W # #.X.g.$ w _ /.. W..XS./XmX0XsX2Xy.b X v v v v v v v v.) o o o n n.E + @ {.P.i",
+".iXpXpXpXpXp % % )X#Xz ..N k k k k k 2 2 2.W # # # &.X.gX7 < _.(Xm.t _./..Xm./XSX0X8 u.H.b f f - - - - v v v.).I o.Y Q.T.E @ $.i",
+".iXdXdXdXfXfXfXf 1. l m.Z k k k z z z z.W.W # # & &.X.gX7.$ WX0 _ w WXmXmXm./.(...t.. /.-.-.HXg.q.q - - - f X v.) o o.Y Q.E @.i",
+"XaXfXfX@.;X@.^.U.a l.x.N.Z k k z z z z.W.W # & &.X.X.g.o `X7 w W.t w W.. _ W...(Xm = _X0X0./.( a.q.H.q.q.q -.L f X.I.I o.Y Q.T.F",
+".; 6 6 6.} 6.^.UXz . m k k z z z z.W.W.W # # &.X.s.g.o.o.@.@X7.$.$ < W.a _ w _.( _ w.KX8XX.t.. /.H x xXd.H.q.q.q.L f X.I o.Y Q +",
+" H.V.V.V.v.V.^.U lX+ m z z z z.W.W.W # # & &.X.s.g.o.o NXl.@.`.`XAX7 w W.t <XX./.K.{ c = c wXX uX2XsXsXs.bXs.b.b.h f f X.I o.Y.T",
+" H G G.v.| G.^.U l m.Z z.W.W.W.W # # # & *.X.s.g.o.o N NXlXlX%X%.C qXA.$.=.= =X8 =.=.y.y.y.=Xe.9X0 u u uXSXS / 3 /XsXs f X.I o Q",
+" H H H H [XZ.u _.x.Z 2.W.W # # # # & *.X.s.s.g.o.o N NXl.@X%XbX* 0 q.`.`XAX:.Q =.QX:X:X:X: i.QXeXe.K.K.KXX _XXXXXi..X0Xs f X.I.Y",
+" KX>X>.^.^ R jX+X7 2.W # # # & & * *.X.s.g.g.o.o N NXlXlX%X%X*X* F F 0 0 q ~ MX7.`XqXq ~.R.RX:X7X7.= p.$.$ <.$ p.QX+X$.^.^ f X o",
+" LX<X<.^ h R jX+X7 2 | # & & * *.X.s.g.g.o.o N NXlXl.@X%XbX*X* F F 0 0 q q ~ MX7.`XqXq ~.R.R.`X7X7.= p.$.$ <.$ p.QX+X$.^.^.q f.I",
+" s L L L.~ R j <X7 | | & * *.X.X.f.g.o.o.O NXlXlXlXlX%X%X*X* F F 0 0 q q ~ ~ M.yX:.RXq ~.R.R i.y.=.= p p p.{.{ p.Q c j 3.b.q.L X",
+".<XNXNXN.| J.6X$.t ` `.X.X.s.f.g.o.o.O.O NXlXl ZX%X%XbX*X* F F 0 q ~.`XAX:X:.Q =.Q i iX: i i.QXeXe.K.K.K jXi j.K _X8.uXx.TX4.q f",
+".2.<.<.<.<XN.^.^Xi.$ `.f.g.g.o.o.O.O N NXlXlX%X%X%X%X*X* F F 0 0 ~.RXA.$.=.= =Xm =.=.=.y.= pXe././.a.a.(. . .(.(.(X9 1.- a.H.q f",
+" VX6X6X6XBXB h.^X8 <X7.o.o.o.O.O NXjXlXlXlX%X%XbX*X*X* F q !.`XAXA.y w W.t < W./ W.{ c = c w _. . X# B B D DX9 1 1 1 e.- a a.H.L",
+" b U U U U U h.^.9 w.$ N N.O N NXlXlXlXlX%X%XbXbX*X* F F ! ~XA.$.$ < W.a l w l.a l w.KXm W.tXz.[ 4X3 P d d Y.4 9 E E.8 e.- a.H.L",
+".i.2.2.2.2.2Xh } 3X8.tX7 `XjXlXlXl ZX%X%XbX*X*X* F F.7 qXA.= w W.t w WXz l WXz.a l.t l.aXzXz.j.[X3.GX1X3 P.1.n.4 9 EX- e e a a.i",
+".iXV.2.2.3XVXV.2 JXyXi.$X7XlXlXlX%X%XbXbX*X* F F F F ! ~.=.Q W.a l w W l l lXz.jXz.tXz.[.[.[XnX,.D.D.D.GX3 P.1.n B.BX-.8 e.-.c.i",
+".i.AXVXVXVXV h h.d JX8 <.$.CX*X%X* F !.R ~ q.7 0 0 q.RX: c.K... Xm.t lXzXz lXz.[.aXm.a.*.[.[Xn tX;X;X,.DX1X3 P.1.4 9 EX- e e.h.i",
+".i yXVXCXCXC h h : .9 w <.C.CXb F 0 MX: M q q 0 q q M.yXe.u.(X9./ WXz. Xz l.a.[.[. .[X; t.S.S.S.S.*X;Xn.DX1X3 4.n B.BX-.8 e.h.i",
+".i.i 8 8 8 8 h hXk.P RX8.tXA.`X* ~ M.{ =.Q.=X: ~ ~ ~.y.{.K uX9 D. ./.a. ./ WXz.[.[.[Xn.0.SX=X=X=X=.S.SX;Xn.,XM P.1.4 9X-.8.-.i.i",
+".i.i y 8 8 8 h h 8 b J RXi.$XAX* M.y =X8Xe.Q.=.R.R.R.=.Q j.(X- E.B BX#X#./ WXz.z.,.0.S.SX=X=X=X=X=X=.S.SX;.D.,X3.1.n 9X-X-.b.i.i",
+".i.i.i 8 8 8 8.5.M A.P JXi.{.$.`.y.=Xe.uX8Xi =XAXAXA = _.9 / e.e EX- BX.. Xz.j.[X,.0.SX=X= S C C C SX=.%X;Xn.,XM 4.n B.BX-.i.i.i",
+".i.i.iX&.5.M.M.M.M.M ] JX8 <.{.$.= p j R R 3XX.{.{.{ _.(XS e O E E ' Y dXM.[.[X, t.SX=X= S C C C C CX=X=.SXn.DXM 4.n B.B 1.i.i.i",
+".i.i.i y.M.M h h.M , ] JX8 w =XX =.{ j R RX2 _.{.{.{ _X9XsXw O E E T Y Y.1 4XM.D t.SX=X= C C C C C C SX=.SXn.DXM 4.n B.BXs.i.i.i",
+".i.i.i.i.#.M h h A , ] J.9 cXi.uXi c j R RXy _ < < <Xm 1.cXw O E E ' Y d PX3.DX, t.SX=X= C C CX5 C C SX=.SXn.DXM 4.n BX-.i.i.i.i",
+".i.i.i.i.iX& A A A A ].F.9XeX8 3Xi cX8 RXyXyX8.Q.Q <Xm 1.cXw O.e E ' T d dX3X1.DX;.SX=X= C C C C C CX=.z.*Xn.,XM 4.n D.i.i.i.i.i",
+".i.i.i.i.i y A A A A ].F.u.K.9 RX8 =.9XuXyXyX8 c.Q <Xm 1.cXw O.e E 9 T Y dX3.G.DX;.*.SX= S C C C C SX=.%X;Xn.,X3 4.nXs.i.i.i.i.i",
+".i.i.i.i.i.i , AXvXv ].P R.u 3Xx.9Xe.9.h.h 7.u j =.QXm 1.c ) O.e E E T Y d PX1.DX,X;.S.SX=X= S SX=X=.z.*Xn.DXMX..1 D.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.#X&X&.#.+.P J J.u.KX0.hXZ QXy.u j c.. 1.c )Xw O E E 9 T.1 dX3.G.DXnX;.S.%X=X=X=.z.%.*XnXn.,X3 4 B.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.iX ,X&X&.#Xv.k.P R.uX2XZ.E nXx u j =.. 1.H )Xw e.e E E T.4 d PX3X1.DXnX;X;.S.S.S.*X;XnXn.,XM 4.nXs.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.iX ,.#.#Xv.+ :.d.F.T @ @ @ nXZ RX8Xe./.-.H a ) e O.8 E 9 T Y.1 PX3X1.,.DXnXnXnXnXnXn.D.,XMX..nXs.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.iX ,.#.#.+XkXh.d.~ } $ [ n.TXx.u.9.(.c.q x )Xw O.8 E E 9.4.n.1 PX3XM.,.,.D.D.D.,.,XMX3 4.nXs.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.iX ,.#XvXkXh.d.p } $ { +.T.Y.h.b.b.q.q x a )Xw e.8 E E 9.4.n.1 4 PX3XMXMXMXMXMX3X. 4.nXs.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.iX ,Xv.+ :XO.| }Xa { [.E n.Y.Y.I f.q.q x a ) e e.8 E E 9 B.4.n.1.1 4 4 4 4 4 4.1 BXs.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.].+ :Xh.d.p } $ @ + n.Y o.I f.L.q.H a aXw e e.8 E E.B 9 B.4.n.n.n.n.n.n.n D.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i y ] :XO.d }Xa { @.E Q o.I X f.L.q.H a aXw e e.8X-X- E.B 9 9 B B B B DXs.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i ]Xh.d.p } $ @ +.T.Y o.I X f.L.q.H a aXw e e e.8X-X-X-X-.B.B.BX-.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.A :.d.~Xa $ @.E Q.Y o.I X f.L.q.H a a a.- e e e.8.8X-X- 1Xs.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.A.~ $ { @.E Q.Y o.I X f.q.qX4.H a a a.- e e.-.b.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.P.P $ @.T Q.Y o.I X f.L.q.q.H.H a.c.h.h.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i",
+".i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.F +.T Q.Y o.I X f f.L.L.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i"
+};
diff --git a/arts/builder/pics/Synth_PSCALE.xpm b/arts/builder/pics/Synth_PSCALE.xpm
new file mode 100644
index 00000000..b40b95d5
--- /dev/null
+++ b/arts/builder/pics/Synth_PSCALE.xpm
@@ -0,0 +1,299 @@
+/* XPM */
+static char * PSCALE_xpm[] = {
+"64 64 232 2",
+" c None",
+". c #161E54",
+"+ c #469224",
+"@ c #4A5A94",
+"# c #56CA0C",
+"$ c #2E3E7C",
+"% c #66E614",
+"& c #4EAE1C",
+"* c #428A34",
+"= c #3E4E84",
+"- c #5EDA0C",
+"; c #8692B4",
+"> c #222E64",
+", c #364684",
+"' c #66CE24",
+") c #6E769C",
+"! c #3A7244",
+"~ c #4AA21C",
+"{ c #6EF614",
+"] c #7E86AC",
+"^ c #52629C",
+"/ c #52BE0C",
+"( c #4A529C",
+"_ c #2A3674",
+": c #5AD214",
+"< c #7AFA1C",
+"[ c #469A24",
+"} c #363E84",
+"| c #46568C",
+"1 c #3E4684",
+"2 c #6EDA2C",
+"3 c #969ECC",
+"4 c #767EA4",
+"5 c #1A2664",
+"6 c #424E94",
+"7 c #525A94",
+"8 c #62E20C",
+"9 c #222E74",
+"0 c #5ECA1C",
+"a c #52B61C",
+"b c #8E9ABC",
+"c c #62BE34",
+"d c #66D624",
+"e c #6A76BC",
+"f c #4EAA1C",
+"g c #5A62AC",
+"h c #56C60C",
+"i c #323A84",
+"j c #5ED21C",
+"k c #6AEE14",
+"l c #3A4A7C",
+"m c #72FE14",
+"n c #868EB4",
+"o c #2E3A74",
+"p c #82FA24",
+"q c #4E9A34",
+"r c #36427C",
+"s c #222A64",
+"t c #569254",
+"u c #4E5E94",
+"v c #32427C",
+"w c #528E54",
+"x c #464E8C",
+"y c #66DA1C",
+"z c #8E92C4",
+"A c #5E6AB4",
+"B c #52A62C",
+"C c #3E4A84",
+"D c #2A3274",
+"E c #36428C",
+"F c #4A962C",
+"G c #428E34",
+"H c #62DE0C",
+"I c #767AA4",
+"J c #4EA61C",
+"K c #52669C",
+"L c #5AC21C",
+"M c #4A5694",
+"N c #5ED60C",
+"O c #425294",
+"P c #5ECE1C",
+"Q c #52BA0C",
+"R c #6672BC",
+"S c #162254",
+"T c #469234",
+"U c #4E5AA4",
+"V c #5ACE0C",
+"W c #323E84",
+"X c #66EA14",
+"Y c #4EB21C",
+"Z c #42528C",
+"` c #62DA1C",
+" . c #26326C",
+".. c #3A468C",
+"+. c #6ED22C",
+"@. c #727AA4",
+"#. c #76FA1C",
+"$. c #7E8AB4",
+"%. c #56C20C",
+"&. c #2E3674",
+"*. c #7AFE1C",
+"=. c #4A9E24",
+"-. c #7E82B4",
+";. c #1E2A6C",
+">. c #525EA4",
+",. c #66E21C",
+"'. c #263274",
+"). c #6ED62C",
+"!. c #3A427C",
+"~. c #666EB4",
+"{. c #3E4A94",
+"]. c #4E5694",
+"^. c #4A922C",
+"/. c #4E5A9C",
+"(. c #5ACA1C",
+"_. c #323E74",
+":. c #424E8C",
+"<. c #62DA0C",
+"[. c #8A96BC",
+"}. c #262E6C",
+"|. c #3A467C",
+"1. c #66D224",
+"2. c #7276A4",
+"3. c #4AA22C",
+"4. c #6EFA14",
+"5. c #5662AC",
+"6. c #5ED20C",
+"7. c #9AA2CC",
+"8. c #7A82AC",
+"9. c #56AA34",
+"0. c #6E7ABC",
+"a. c #4E9E2C",
+"b. c #5A66AC",
+"c. c #6AF214",
+"d. c #626EB4",
+"e. c #82FE1C",
+"f. c #8E96BC",
+"g. c #46528C",
+"h. c #6AE624",
+"i. c #56BE1C",
+"j. c #5AC61C",
+"k. c #428E3C",
+"l. c #52BA1C",
+"m. c #1A2264",
+"n. c #525AA4",
+"o. c #3A4A8C",
+"p. c #2E3A84",
+"q. c #222A74",
+"r. c #4EA62C",
+"s. c #56C21C",
+"t. c #468A2C",
+"u. c #8A92BC",
+"v. c #5662A4",
+"w. c #7EFA24",
+"x. c #4A9A2C",
+"y. c #1E2664",
+"z. c #66E214",
+"A. c #62CA24",
+"B. c #929AC4",
+"C. c #6AD624",
+"D. c #62D21C",
+"E. c #76FE14",
+"F. c #8A8EBC",
+"G. c #468E2C",
+"H. c #465294",
+"I. c #62CE24",
+"J. c #1A225C",
+"K. c #529E34",
+"L. c #5ACA0C",
+"M. c #52AE1C",
+"N. c #72F614",
+"O. c #72DA2C",
+"P. c #9A9ECC",
+"Q. c #464E94",
+"R. c #262E74",
+"S. c #56B61C",
+"T. c #626AB4",
+"U. c #3A428C",
+"V. c #6AEA14",
+"W. c #52B21C",
+"X. c #828AB4",
+"Y. c #7EFE1C",
+"Z. c #565EA4",
+"`. c #424A94",
+" + c #4EA22C",
+".+ c #5E66AC",
+"++ c #6EF214",
+"@+ c #56BA1C",
+"#+ c #46922C",
+"$+ c #4A5A9C",
+"%+ c #3E4E8C",
+"&+ c #222E6C",
+"*+ c #6E76A4",
+"=+ c #7E86B4",
+"-+ c #2A367C",
+";+ c #465694",
+">+ c #3E468C",
+",+ c #767EAC",
+"'+ c #62E214",
+")+ c #5ECA24",
+"!+ c #8E9AC4",
+"~+ c #56C614",
+"{+ c #3A4A84",
+"]+ c #868EBC",
+"^+ c #2E3A7C",
+"/+ c #364284",
+"(+ c #222A6C",
+"_+ c #4E5E9C",
+":+ c #324284",
+"<+ c #3E4A8C",
+"[+ c #2A327C",
+"}+ c #5266A4",
+"|+ c #4A569C",
+"1+ c #5ED614",
+"2+ c #2E367C",
+"3+ c #4A9E2C",
+"4+ c #26327C",
+"5+ c #3A4284",
+"6+ c #4E569C",
+"7+ c #323E7C",
+"8+ c #62DA14",
+"9+ c #3A4684",
+"0+ c #66D22C",
+"a+ c #5ED214",
+"b+ c #6E7AC4",
+"c+ c #82FE24",
+"d+ c #8E96C4",
+"e+ c #1E266C",
+"f+ c #6AD62C",
+"g+ c #62D224",
+"h+ c #76FE1C",
+"i+ c #46529C",
+" '.D D [+[+'.R.9 q.(+;.y. ",
+" s o /+/+i p.^+-+4+R.'.R.9 9 (+9 m.. . . ",
+" &.C `.>+U./+W p.2+2+-+4+'.R.q.9 ;.;.;.e+m.m.. . ",
+" o /.6+M Q.`...E } i p.^+-+4+R.9 9 9 q.9 9 q.;.;.5 m.. . . . ",
+" 7 Z.>.6+( 6 {...E :+i 2+-+-+-+[+'.R.9 q.;.;.;.;.q.;.;.e+e+m.. . ",
+" ].T..+5.n.6+H.6 `.>+E } W p.2+[+'.'.R.9 &+9 q.q.q.e+;.;.e+;.e+;.m.. . . ",
+" d.d.A g Z.U |+Q.`.>+..E W i p.2+[+4+4+R.R.q.&+;.;.q.e+;.;.e+;.e+;.e+5 m.. . ",
+" x e R T.b.5.>.U |+i+{.o.U.} i $ ^+-+-+D '.'.9 9 q.9 q.;.q.e+e+;.e+;.e+e+e+e+m.. . . ",
+" !.*+R R T.b.v.n.|+( Q.`.>+../+i p.^+-+4+4+R.9 R.9 q.&+q.;.;.;.e+;.e+e+5 e+e+5 e+m.. . . ",
+" ].0.R R T.b.g >./.|+H.6 <+..E } W 2+-+[+[+R.4+R.9 (+q.;.;.;.;.;.;.e+;.;.;.e+;.;.e+;.m.. . . ",
+" !.*+e ~.d.A b.Z.n.6+i+6 {.>+U.E W W p.2+_ [+R.R.9 9 &+q.9 q.;.;.e+q.e+e+e+;.5 e+;.5 e+5 m.. . . ",
+" x e R R ~.A b.Z.>.U |+i+6 {.../+W W ^+2+-+[+'.'.'.R.9 ;.q.;.;.e+e+;.e+;.;.e+e+e+5 e+e+;.e+e+m.. . . ",
+" R e ~.d..+b.5.>.U |+H.Q.`.<+..E W i ^+^+-+-+4+9 9 9 9 9 ;.;.;.q.;.;.e+e+;.;.;.;.e+;.e+5 e+5 5 m.. . ",
+" R R ~.7.P.b.g >.U |+( Q.%+<+U.E } i p.p.-+-+'.R.R.R.q.q.;.q.q.q.;.q.;.;.;.;.;.;.;.;.;.;.;.;.e+e+;.m.. . ",
+" C ~.~.T.3 3 Z.>.n.6+i+Q.`.>+..U./+} i 2+-+[+[+'.'.9 R.}.9 9 9 9 9 ;.9 9 9 9 ;.q.q.9 q.9 9 q.9 ;.;.;.;.5 m.. ",
+" T.T.b.b.5.>.>.n.|+( i+6 `.o.../+} W ^+^+-+-+'.4+R.R.9 9 q.q.;.&+q.9 9 9 9 9 9 9 9 9 &+(+(+&+(+9 (+q.(+;.. . ",
+" ].b.g 5.5.Z.U U 6+;+Q.6 {.>+..U.W W i 2+2+-+[+'.4+'.9 9 R.9 '.9 '.R.9 9 9 R.'.'.'.}.'.'.'.9 '.&+9 &+&+q.&+;.5 . ",
+" } g Z.^ >+n.d+d+|+i+Q.6 {.{...U.W W w t ^+-+'.'.'.R.9 '.R.'.'.R.R.9 '.'.'.'.'.R.'.'.'.'.'.R.'.R.'. .R.9 }.9 (+(+J.. ",
+" x >.n.U ..|+z u.i+6 `.{...U.E E } $ +.).-+-+[+4+'.'.R.'.'.'.'.'.D '.D '.D '._ '.'.-+'.'._ '._ '.'.'. .'.}.'. .&+(+5 ",
+" U 6+6+6+5+( ; ]+6 `.{.>+U.E } W p.i +.w.).B '.D 4+D '.'.'.'.4+4+'.'.4+_ _ -+4+-+_ D -+_ '._ '.D D _ D '.'.R.R.&+ .J. ",
+" &.( i+i+Q.} Q.]+X.{.>+U...5+} i W ^+^++.e.c+C.'.'.4+-+D [+[+_ _ -+-+_ -+-+_ ^+&.-+^+_ -+^+-+o -+-+_ -+_ _ _ '.D }.D &+5 ",
+" Q.O 6 6 6 %+{.>+>+.., U.} W W W ^+2+-+2 c+e.< 1.B '.'.-+'._ [+-+_ 2+2+2+-+2+-+^+^+-+^+^+-+^+-+o ^+_ _ _ _ _ _ _ _ .> . ",
+" y.`.`.{.{.>+>+>+>+U.U./+} W W i 2+p.c C.w.Y.Y.Y.Y.d -+'.-+[+-+_ -+^+^+^+^+^+^+^+^+$ ^+^+7+^+$ ^+^+^+^+^+2+-+_ _ _ _ D _ .y. ",
+" o ....>+U...p...=+=+} W W W ^+2+^+-++.e.e.w.C.d #.N.D. +-+o ^+-+^+^+-+^+^+^+^+^+^+i $ $ ^+$ i $ ^+$ ^+^+^+o ^+_ -+_ _ D > . ",
+" } 5+E U.E } -+:+=+=+W i i 2+p.2+-+_ 0+Y.Y.d [+4+1.h+h+D.-+-+^+^+^+$ ^+$ $ $ W 7+$ W 7+v 7+7+7+7+7+7+7+$ 7+^+i o &._ _ &.D . ",
+" } E } :+} W [+i -.8.p.^+-+^+-+[+D 4+' Y.*.A._ -+r.D.#.{ P ~ ^+^+^+^+$ 7+W W 7+W /+} } W } :+W :+7+W 7+7+$ 7+$ ^+$ ^+o _ _ D ",
+"'.W W i W W i D ^+,+8.p.2+-+-+-+4+D '.I.*.*.)+_ -+-+-+j m m P p.^+W i W 7+} :+r W v :+/+/+/+r /+/+r :+/+} 7+7+7+^+7+^+o o o o _ ",
+"'.^+p.p.2+p.^+^+p.^+2+-+-+[+D '.D '.[+1.#.1.B [+_ -+-+r.h.{ c.(.3+7+v W W :+/+/+, /+, , , /+, /+/+/+/+r :+r /+r v 7+7+7+^+o _ _ ",
+"[+2+2+p.2+-+-+-+[+[+[+-+4+4+4+'.R. +d N.D.-+_ -+2+^+^+^+p.,.{ { j.W :+/+/+/+/+/+9+5+5+, 9+9+9+9+, 9+, 9+/+/+:+} 7+7+7+$ ^+o o &.",
+"'.-+-+[+-+-+[+&+-+4 4 '.'.'.R.9 9 A.E.h+P '.-+2+-+-+2+p.W +0 k k j.x./+/+/+, 9+, , o.9+9+...., 9+9+.., , , !., /+/+7+7+7+7+^+^+",
+"D [+-+'.[+-+[+q.4+I I 4+R.'.R.R.9 )+h+h+)+[+D ^+o ^+^+^+i $ :+j.c.k j., , , , ..o.9+>+o.{+{+<+o.o.9+9+9+9+, /+, r /+r v 7+$ ^+o ",
+"R.'.R.4+'.R.'.(+4+@.@.R.9 R.9 9 R.0 m m )+_ -+-+-+^+^+i $ W W =.y k % L x.....o.<+o.o.<+<+<+o.<+C o.<+o.{+o.{+9+, , /+} v 7+7+^+",
+"R.4+R.R.4+9 '.(+'.@.@.R.q.9 9 9 9 P { P 3+-+_ ^+^+^+$ W 7+/+/+/+/+d X X i.C o.o.<+%+%+%+%+:.%+%+%+%+= <+C 1 {+9+9+, , r r v v 7+",
+"9 9 9 9 9 R.9 9 9 R.9 9 9 &+9 =.0 { 0 '._ _ 2+-+p.^+$ 7+/+W /+:+, =.%.z.z.i.F <+%+<+<+%+%+%+:.%+:.%+`.%+<+%+<+o.9+9+9+5+r } } ^+",
+"q.R.R.9 9 q.q.q.9 q.9 (+q.(+9 L { { L 4+-+-+^+^+^+i W 7+r :+/+/+, ....i.8 8 @+%+:.Z 6 6 Z Z 6 :.:.Z %+%+<+<+= <+C 9+{+, , r r 7+",
+"(+9 9 (+q.}.9 ;.;.@.*+9 q.q.;.s.{ { s.D _ -+-+-+$ $ 7+W :+/+9+9+....{+x.D.z.<.a F 6 Z Z O O g.Z O :.Z Z Z = `.= o.{+9+9+9+r r 7+",
+"e+;.9 &+;.q.(+;.(+@.*+;.;.q.9 j.{ { s.4+_ o ^+^+i W :+W /+/+, 9+{+o.o.%+o.j 8 H l.O H.H.H.;+;+H.;+O O Z O Z %+:.<+o.{+9+9+, , r ",
+";.q.q.;.q.;.;.e+;.2.2.;.;.;.q.` X L [ _ -+-+^+^+$ $ 7+/+/+, E o...<+<+%+:.F @+1+6.W.#+| ;+H.H.;+H.;+H.O g.Z Z %+:.= <+{+{+9+!.7+",
+" ;.q.;.q.q.(+e+;.@.@.q.(+[ d k ~+R.4+_ -+-+^+^+i W 7+/+/+9+, o.9+<+<+%+%+6 Z a <.- W.;+@ @ ;+@ ;+;+M ;+H.H.g.Z :.%+<+{+9+, 9+ ",
+" ;.;.q.;.;.;.;.;.e+e+;.;.l.k V.@+'.D 4+_ ^+^+i 7+7+/+:+/+, ..1 o.%+%+O O Z O F a a+V Y G ;+@ ;+M @ ;+;+| O Z :.:.:.%+C C 9+, ",
+" . y.;.;.e+q.e+;.;.e+e+;.Q k X @+'._ -+_ -+^+$ W W r , /+9+o.<+o.<+%+:.O H.O ;+;+a N 6.W.$+/.@ @ @ @ ;+M ;+;+g.Z :.%+%+C 9+_. ",
+" m.;.;.;.;.e+e+;.2.*+;.;.l.% X l.'.'.D -+^+^+i 7+v /+/+.., 9+o.<+%+:.O O Z ;+;+M G.M.V L.& G._+/./.@ $+@ ;+| ;+Z Z :.C C |.> ",
+" m.e+;.;.;.5 ;.2.*+e+e+j H l.+ '.-+_ _ ^+^+$ W W /+/+..o.{+<+%+%+:.:.H.H.;+;+@ @ $+& V V f _+u /.u @ @ ;+;+H.Z :.:.%+{+1 ",
+" m.;.e+e+e+e+e+) 2.! a+% l.&+9 R.'.-+-+o $ p.7+v :+, /+9+..%+<+%+O O | ;+;+@ $+_+_+G.M.h h f G _+$+$+$+M | ;+g.Z Z = = . ",
+" m.;.;.e+5 ;.) ) k.8 % W.}.'.'.'.-+-+2+7+i W } r 9+, {+9+<+<+%+Z O ;+H.;+;+@ @ _+_+^ & # L.f ^ u /.u @ ;+;+;+Z :.:.:. ",
+" e+5 e+e+e+e+e+e+G.8 H Y 9 R.'._ _ -+o ^+$ 7+v :+/+9+..o.%+%+:.:.Z H.;+;+@ $+_+_+_+_+G.i.h %.J t._+$+@ @ ;+Z Z Z = !. ",
+" . 5 ;.;.5 5 e+5 * '+8 Y &+R.'.D _ -+^+^+7+W } /+/+9+9+..<+<+:.6 Z ;+;+|+;+@ /.u _+^ ^ ^ l.%.%.J u /.@ @ M H.g.:.= 1 ",
+" e+5 5 e+e+*+*+* H H & &+'.'._ -+o -+7+^+7+v :+, /+{+{+%+%+%+Z O H.;+;+@ $+u _+^ ^ }+}+G.J / Q ~ x./.M ;+| Z Z l ",
+" m.e+e+e+2.2.* 8+<.~+(+&+R.'.'.o _ ^+i 7+r /+, /+..9+<+%+:.Z Z g.;+;+M $+$+_+_+>.^ K K ^ 3+%./ / @ @ ;+g.g.:. ",
+" m.;.5 5 *+) *+*+;.&+@.@.4 4 _ -+8.8.] 8.W :+=+X.X.X.o.<+n n ]+; ;+M [.[.f.[._+^ B.B.!+!+^ _+f.[.[.u.g.| Z &. ",
+" S e+e+*+) ) 2.;.(+@.@.I ,+D _ 8.4 ] ] 7+r ] $.X.X.<+<+n n ]+u.;+;+u.[.f.[.u _+b B.b d+_+_+f.f.[.[.g.Z :. ",
+" e+5 e+5 e+;.e+&+q.9 '.'._ _ _ ^+^+$ 7+W /+r , 9+{+o.<+:.Z Z Z H.M @ @ /.$+$+u _+_+u u u @ @ ;+g.| Z ",
+" . . e+5 m.y.e+(+;.;.;.(+_ -+ .'.D D 7+v o &.o ^+C o.7+7+7+v Z | v r , |./.@ 9+9+{+9+$+/.r !.;+Z x |. ",
+" J.5 e+5 5 ;.;.(+&+}.'.'._ -+_ ^+$ 7+W W , /+9+{+C {+<+:.:.O O H.;+;+;+@ @ @ /.@ @ @ @ @ ;+| g._ ",
+" . J.e+5 ;.;.(+9 &+'.'.D 2+_ o $ 7+v 7+/+, /+, <+C <+%+:.Z Z Z g.;+| ;+;+@ M @ ;+;+| ;+g.Z |. ",
+" . 5 e+y.(+(+&+R.}.'._ _ 2+o i ^+7+:+v /+, 9+9+o.= <+%+:.Z g.O g.H.;+| ;+;+| | | H.| Z &. ",
+" . S 5 ;.(+&+9 }. .'._ -+_ o ^+i 7+7+/+, , , ..C C <+`.%+Z Z Z g.H.g.| H.;+H.| Z Z |. ",
+" y.;.;.;.&+9 R.'._ _ ^+o o 7+7+r r r /+9+, {+o.= = :.:.%+Z :.Z Z O Z Z Z Z = ",
+" . ;.;.&+&+ .}.D '.-+o o $ ^+7+W r r 9+5+9+9+o.{+C %+%+%+:.:.:.Z :.Z :.C ",
+" ;.(+&+9 '. ._ _ _ ^+^+7+$ 7+v /+r , 9+, 9+1 o.C C :.%+%+= :.:.C ",
+" y.s &+R. .D D _ &.o i _.7+7+v r r 9+, , {+{+<+{+C C %+C C |. ",
+" s R. ._ D _ _ o ^+^+$ W 7+:+r !.9+9+9+9+9+{+l r ",
+" s > D _ _ o ^+o ^+7+7+7+:+r r r , 9+_.v ",
+" D _ &.^+o o 7+7+7+7+} r "};
diff --git a/arts/builder/pics/Synth_RC.xpm b/arts/builder/pics/Synth_RC.xpm
new file mode 100644
index 00000000..a906535e
--- /dev/null
+++ b/arts/builder/pics/Synth_RC.xpm
@@ -0,0 +1,323 @@
+/* XPM */
+static char * Synth_RC_xpm[] = {
+"64 64 256 2",
+" c None",
+". c #161E54",
+"+ c #42862C",
+"@ c #2E524C",
+"# c #366E34",
+"$ c #56BA24",
+"% c #263A54",
+"& c #4EA22C",
+"* c #4A529C",
+"= c #2A4654",
+"- c #768694",
+"; c #626E84",
+"> c #62D61C",
+", c #365E4C",
+"' c #1E2E54",
+") c #3A467C",
+"! c #323A84",
+"~ c #52629C",
+"{ c #46962C",
+"] c #467A4C",
+"^ c #425284",
+"/ c #2A3274",
+"( c #8A96BC",
+"_ c #3E4E84",
+": c #5ECA24",
+"< c #9AA2CC",
+"[ c #52AE2C",
+"} c #4A5A8C",
+"| c #727AA4",
+"1 c #66E21C",
+"2 c #4A765C",
+"3 c #66866C",
+"4 c #2A3A6C",
+"5 c #263664",
+"6 c #1A2664",
+"7 c #364674",
+"8 c #868EAC",
+"9 c #425E64",
+"0 c #3A468C",
+"a c #32427C",
+"b c #468E34",
+"c c #426E54",
+"d c #5EAA3C",
+"e c #222E6C",
+"f c #465A7C",
+"g c #5AC224",
+"h c #66DE1C",
+"i c #525A94",
+"j c #3A526C",
+"k c #52AA2C",
+"l c #2E4E51",
+"m c #425294",
+"n c #626EB4",
+"o c #5662AB",
+"p c #4A9E2C",
+"q c #1E266C",
+"r c #3E5E5C",
+"s c #5ED21C",
+"t c #7A82AC",
+"u c #3A427F",
+"v c #62C62C",
+"w c #3E7644",
+"x c #2A425A",
+"y c #56A634",
+"z c #2E465C",
+"A c #6AD624",
+"B c #3A4A84",
+"C c #567A5C",
+"D c #2A3674",
+"E c #969ECC",
+"F c #464E93",
+"G c #4A5A9C",
+"H c #2E3A7D",
+"I c #868EBC",
+"J c #263273",
+"K c #5AC61C",
+"L c #5E6AB4",
+"M c #4A8644",
+"N c #3A6E44",
+"O c #4EA62C",
+"P c #4A5694",
+"Q c #7E86B1",
+"R c #366640",
+"S c #4E963C",
+"T c #425680",
+"U c #6E7AC0",
+"V c #72EA24",
+"W c #424A94",
+"X c #4E8E44",
+"Y c #6E76A4",
+"Z c #325A4C",
+"` c #263A5C",
+" . c #2A4A4C",
+".. c #62DA1C",
+"+. c #263264",
+"@. c #323E7C",
+"#. c #4A824C",
+"$. c #8E9ABE",
+"%. c #424E94",
+"&. c #66CA2C",
+"*. c #56B62C",
+"=. c #6EE624",
+"-. c #222A64",
+";. c #426664",
+">. c #3A4A8C",
+",. c #36428C",
+"'. c #4A9236",
+"). c #42764C",
+"!. c #3E5A64",
+"~. c #5E66AC",
+"{. c #2A367C",
+"]. c #4A569C",
+"^. c #162254",
+"/. c #428A34",
+"(. c #32623C",
+"_. c #223254",
+":. c #4A9A30",
+"<. c #4A7A4C",
+"[. c #424E8C",
+"}. c #767EA9",
+"|. c #6AE61C",
+"1. c #5A6E74",
+"2. c #2E3E6C",
+"3. c #1E2A64",
+"4. c #364282",
+"5. c #262E73",
+"6. c #5EC228",
+"7. c #6EDE24",
+"8. c #525EA4",
+"9. c #626A84",
+"0. c #6A76BC",
+"a. c #567664",
+"b. c #6E8684",
+"c. c #42665C",
+"d. c #6A7299",
+"e. c #465E7C",
+"f. c #364E64",
+"g. c #8E92C4",
+"h. c #427E3C",
+"i. c #42724C",
+"j. c #3A5664",
+"k. c #529E38",
+"l. c #66D22C",
+"m. c #32564C",
+"n. c #3A723C",
+"o. c #5ABE27",
+"p. c #223E4C",
+"q. c #56B22C",
+"r. c #4E5E94",
+"s. c #465694",
+"t. c #6672BC",
+"u. c #5A66AC",
+"v. c #1E2A6C",
+"w. c #324A64",
+"x. c #4E5E9C",
+"y. c #3A7244",
+"z. c #7E8AB4",
+"A. c #2A3E5C",
+"B. c #5ECE24",
+"C. c #628A6C",
+"D. c #5A7E5C",
+"E. c #8A92BC",
+"F. c #768A8C",
+"G. c #8692B4",
+"H. c #2E3E7C",
+"I. c #4E9A34",
+"J. c #5A726C",
+"K. c #426264",
+"L. c #6ADA24",
+"M. c #66CE2C",
+"N. c #4A7E4C",
+"O. c #222E64",
+"P. c #5EC62C",
+"Q. c #46568C",
+"R. c #323E84",
+"S. c #1A2264",
+"T. c #36624C",
+"U. c #3E5674",
+"V. c #364684",
+"W. c #465A8C",
+"X. c #525AA4",
+"Y. c #3A428C",
+"Z. c #26327C",
+"`. c #223264",
+" + c #325254",
+".+ c #52A234",
+"++ c #66D624",
+"@+ c #3E4684",
+"#+ c #4A9634",
+"$+ c #46528C",
+"%+ c #8E96BE",
+"&+ c #56AE34",
+"*+ c #6AE222",
+"=+ c #2E3A73",
+"-+ c #1E2664",
+";+ c #4A8E3C",
+">+ c #466E5C",
+",+ c #62AA44",
+"'+ c #6ADE24",
+")+ c #3E5274",
+"!+ c #56AA34",
+"~+ c #465296",
+"{+ c #5A62AC",
+"]+ c #62D224",
+"^+ c #7E82B4",
+"/+ c #3E4A84",
+"(+ c #2E3674",
+"_+ c #4E5AA2",
+":+ c #5EC624",
+"<+ c #4E864C",
+"[+ c #3E6E4C",
+"}+ c #52A631",
+"|+ c #4E5694",
+"1+ c #365A54",
+"2+ c #2A3A64",
+"3+ c #2E4A50",
+"4+ c #46666C",
+"5+ c #3E4A8E",
+"6+ c #467654",
+"7+ c #1A225C",
+"8+ c #468A37",
+"9+ c #222A6F",
+"0+ c #2E4654",
+"a+ c #767AA4",
+"b+ c #3E468C",
+"c+ c #666EB4",
+"d+ c #9A9ECC",
+"e+ c #8A8EBC",
+"f+ c #626AB4",
+"g+ c #7276A4",
+"h+ c #66DA1C",
+"i+ c #5AB62C",
+"j+ c #2E367C",
+"k+ c #4E569C",
+"l+ c #36623C",
+"m+ c #565EA4",
+"n+ c #3E7244",
+"o+ c #828AB4",
+"p+ c #62CE24",
+"q+ c #363E84",
+"r+ c #4EA234",
+"s+ c #62D624",
+"t+ c #3A4684",
+"u+ c #42528C",
+"v+ c #2A327C",
+"w+ c #3E4E8C",
+"x+ c #4A5A94",
+"y+ c #26366C",
+"z+ c #36467C",
+"A+ c #868EB4",
+"B+ c #324284",
+"C+ c #468E3C",
+"D+ c #222E74",
+"E+ c #5AC22C",
+"F+ c #66DE24",
+"G+ c #52AA34",
+" J / / v+v+J 5.D+9+9+v.-+ ",
+" -.=+4.4.! H H {.Z.5.Z.5.D+D+9+D+S.. . . ",
+" (+/+W b+Y.4.R.H j+j+{.J Z.5.9+D+v.v.v.q S.S.. . ",
+" =+i k+P F W 0 ,.q+! H H {.Z.5.D+D+D+9+D+D+9+v.v.6 S.. . . . ",
+" i m+8.k+* %.5+0 ,.B+! j+{.{.{.v+Z.5.D+9+v.v.v.v.9+v.v.q q S.. . ",
+" |+f+~.o X.k+~+%.W b+,.q+R.H j+v+J J 5.D+D+D+9+9+9+q v.v.q v.q v.S.. . . ",
+" n n L {+8._+].F W b+0 ,.R.! H j+v+Z.J 5.5.9+D+v.v.9+q v.v.q v.q v.q 6 S.. . ",
+" [.0.t.f+u.o m+_+].~+W >.Y.q+! R.H {.{.v+Z.Z.D+D+9+D+9+v.v.q q v.q v.q q q q S.. . . ",
+" u Y t.t.L u.o _+].* %.W b+0 ,.! H H {.Z.J 5.D+5.D+9+D+9+v.v.v.q v.q q 6 q q 6 q S.. . . ",
+" |+U t.t.f+~.o 8.X.].~+%.5+0 ,.R.R.j+{.v+v+5.Z.5.D+9+9+v.v.9+v.v.v.q v.v.v.q v.v.q v.S.. . . ",
+" u d.0.c+n L u.m+_+k+* %.W 0 Y.,.R.H.! {.{.v+5.5.D+D+D+9+D+v.v.v.q v.q q q v.6 q v.6 q 6 S.. . . ",
+" [.U 0.t.c+L u.m+8._+].~+%.5+b+,.q+R.! {.j+/ J Z.Z.5.D+v.9+v.v.q q v.q v.v.q q q 6 q q v.q q S.. . . ",
+" c+t.c+n ~.u.o 8.X.].~+%.W >.0 ,.R.H H H {.{.J D+D+D+D+D+9+9+9+v.v.v.q q v.v.v.v.q v.q 6 q 6 6 S.. . ",
+" t.t.t.< d+u.o m+_+].* F %.5+Y.,.q+! ! H {.{.Z.5.5.5.9+9+v.9+v.v.9+v.v.v.v.v.v.v.v.v.v.v.v.v.q q v.S.. . ",
+" /+c+f+f+E E m+8.X.].* %.W b+b+Y.,.R.! j+{.v+v+J Z.D+5.5.D+D+D+D+D+9+D+D+D+D+v.9+9+D+9+D+D+9+D+v.v.v.v.6 S.. ",
+" f+f+~.u.{+m+8._+].* * %.W >.0 ,.R.R.H H {.{.J Z.D+D+D+v.9+v.9+D+9+D+D+D+D+D+D+D+D+D+D+9+9+D+9+D+9+9+9+v.. . ",
+" |+u.u.o o 8.X._+k+].%.%.W 0 0 Y.q+R.H j+j+{.v+J 5.+.@ R R 3+`.D+D+5.5.D+5.5.J J J 5.J J J e `.5.D+e e 9+e v.6 . ",
+" q+{+o 8.b+_+%+%+].* %.%.W >.0 ,.R.R.! H H {.Z.J D+3+[ ++]+B.]+:.5 D+J Z.J J Z.5.J J J J J 5.Z.5.J J 5.D+5.D+9+9+7+. ",
+" F i X.X.b+].g.E.m %.W 5+b+Y.Y.4.R.! ! {.{.{.v+J x v *+b 3+@ p |.[ 5 5./ Z.J D Z.Z.y+Z.J y+/ y+J J J J J 5.J J e 9+6 ",
+" _+k+k+].4.* E.I %.W 5+0 Y.,.q+R.! H {.j+v+/ J +.}+V '.+.J D+` k |./.J J D {.Z.D {.v+D D v+{./ v+/ y+/ J J 5.5.5.`.7+ ",
+" (+s.s.* F R.%.I o+W 0 Y.0 ,.R.! R.H H {.{.v+Z.J m.'+P.` J {.v+J = p+]+3+D D =+j+(+4 {.{.4 {.H D D {.D D D y+J J 5./ e 6 ",
+" F F %.%.%.%.W b+b+0 0 Y.q+q+R.R.H H j+{.v+J / J !+=.n+J Z./ {.D J /.|.+ y+j+{.H H j+H H j+H D H H (+{.D D D D D D J O.. ",
+" -+5+W W 5+b+0 b+0 Y.,.,.R.R.R.! j+j+{.{.v+{.J / A.A ++A./ {.{.{.j+D l F+6.4 H H H H.H H H.H H.H H H =+H j+(+(+D D D / D J -+ ",
+" ! b+0 0 Y.0 H 0 Q Q q+R.R.R.! j+H {.v+v+y+J {.J R *+k J {.D {.D H H y+E+..3+H H H H @.@.H H.! H.H H.H H =+H H D (+D D / O.. ",
+" @.,.,.Y.,.q+{.,.Q Q R.! H j+H j+{.{.v+v+v+v+/ J :.*+N D H H H H H H (+8+F+y.=+R.R.R.R.a @.@.@.@.@.@.@.H.H.H ! =+(+(+D (+/ +. ",
+" ,.q+q+,.q+q+v+! t t H H j+H {.v+{.v+J J Z.J v++.v h+0+D {.{.H H H R.2., h O 2.@.a R.@.q+q+a R.a R.R.@.@.@.@.H.H H.H =+D D / ",
+"5.R.R.! R.R.! v+! }.^+H {.{.{.{./ J Z.Z./ v+y+{.A.A p+2+H H H H H H.! H z s+:+2.q+4.4.B+4.4.4.4.4.4.B+4.@.@.@.@.H H.H =+=+4 4 D ",
+"/ H H ! j+H H H H H {.{.{.v+Z.Z.Z.Z./ v+y+{.v+/ m.h q.D {.H H H R.R.a R.2.: s+w.B+4.V.V.V.4.V.4.4.4.4.4.4.a 4.a a @.@.@.H H (+D ",
+"v+{.{.H {.{.{.{.v+v+v+{.Z./ J 5.5.5.5.Z.J {.{.J y.1 #+=+H H @.@.R.R.4.B+@.$ h+1+4.4.u V.0 t+0 V.V.t+V.V.4.4.4.q+@.@.@.@.! =+=+(+",
+"{.j+{.v+{.{.v+D+{.}.}.Z.J Z.5.J J J J J v+J D D '.*+R =+@.R.R.R.@.B+B+4.a 8+h w z+0 >.0 t+0 t+t+t+t+t+t+t+V.4.z+4.4.@.@.@.@.H H ",
+"Z.v+{.Z.v+{.v+9+Z.a+a+Z.5.J D+D+D+D+5.J v+Z.D D & F+Z H H.H.B+4.q+4.4.t+z+w h+C+z+t+@+>.B >.>.>.>.0 0 0 t+t+4.V.4.4.a a @.@.=+H ",
+"J Z.5.Z.Z.5.J 9+Z.| a+5.D+5.D+D+5.Z.J Z.y+D {.5 :+h+z H @.R.R.R.4.4.0 4.4.1+..&+z+>.>.5+5+5+5+/+5+B B B B >.B t+V.V.4.q+a @.@.=+",
+"5.Z.5.5.Z.D+J 9+J | | D+9+5.9+D+5.J J v+v+{.{.x ++p+A.! @.B+4.B+4.V.0 V.t+f.> : 7 5+w+w+w+w+w+w+w+w+w+5+B b+B t+t+t+V.4.a B+a @.",
+"D+D+D+D+D+5.D+D+D+D+5.D+D+9+5.9+D+5.J J {.D D , h [ =+R.4.q+B+V.V.0 B >.0 7 P.h+j._ 5+w+w+[.[.w+[.[.5+w+5+_ 5+B t+V.V.4.4.q+q+H ",
+"9+5.D+D+D+9+9+9+D+9+D+9+D+v.D+9+D+5.Z.J Z.D D '.F+N 2.R.B+4.4.0 V.0 t+>.>.z+#+h i._ [.[.u+m [.%.w+u+w+[.5+5+w+5+/+@+B ) V.4.a @.",
+"9+D+D+9+9+5.5.v.9+| g+D+v.9+9+D+J J J v+D {.y+o.h+ +H @.4.4.u 4.0 t+5+>.w+B [+..r+B [.m m u+~+u+~+[.u+u+u+[.W _ 5+B t+t+) 4.4.q+",
+"q 9+D+D+v.v.9+v.v.| Y 9+v.v.D+9+D+5.J D D D = ..: 2.R.R.4.V.V.0 >.B 5+5+5+5+j.s+B.j m u+~+s.s.u+s.~+u+u+u+u+w+_ 5+/+B t+t+) z+4.",
+"3.9+9+v.9+9+v.q 9+Y g+v.v.9+9+D+5.J J v+{.D h.1 8+=+@.B+V.,.0 V.t+>.5+w+[.[.B G+h+c u+s.Q.~+~+s.~+s.~+m m u+u+[.w+w+5+B B t+4.@.",
+" v.9+v.v.9+v.q 9+| Y 9+v.v.D+D+D+J J / Z.4 o... +H.q+B+4.V.0 >.5+B w+w+w+[.[.i.h+y [.s.W.W.P W.s.s.P Q.~+$+u+u+w+_ 5+B t+t+) ",
+" v.v.9+9+v.v.v.v.q 9+v.v.9+v.D+5.J {.D D , F+*.4 @.B+4.V.u t+t+>.w+5+u+m ~+u+U.: ]+r s.].].G P P x+s.s.s.m u+F [.w+_ /+B t+z+ ",
+" . q v.v.q v.q v.v.v.q v.9+9+D+5.5.J J 5 q...T.=+R.q+4.V.V.>.0 5+w+w+[.u+m m u+M h k.^ x+x+G G x+x+x+s.P s.s.$+u+[.w+_ B t+@. ",
+" S.v.v.v.9+q q v.Y Y v.v.v.D+e D+J Z.y+R 1 q.=+H.4.B+,.V.0 t+/+5+w+%.m m $+s.u+U.P.]+;.s.G x.r.i _+G x+W.s.s.Q.$+u+[.W /+) O. ",
+" S.q v.v.v.6 q g+g+q v.v.D+5.J J / ` o.> Z =+@.4.4.4.t+>.>.>.5+w+w+[.m ~+s.s.T #...!+T x+x.x.x.x+x.G x+s.s.m m [._ w+B @+ ",
+" S.v.q q q q v.Y Y v.q 9+9+e D+5.`.b 1 :.2+! R.@.B+4.V.t+B w+w+w+u+m ~+s.P x+].)+&+..N.W.x.x.~ x.G x+i P s.Q.$+u+u+_ [.+. ",
+" S.v.v.q q q Y d.9+v.v.D+5.`.e n...*.A.=+H R.4.4.,.V.0 t+5+5+[.u+u+$+s.s.W.G x+4+:+p+6+} x.~ ~ x.G r.x+P s.s.u+[.w+[. ",
+" q q 6 q 6 -+q v.6 q 9+9+e O.n.> g l =+H @.@.R.4.t+0 t+5+>.[.w+%.m s.~+s.P _+x+Q.>+p+: 6+} ~ x.~ x.G x+x+s.$+$+^ _ u ",
+" . q v.q v.q q q v.v.v.3.% { ..$ .J {.H H.@.B+a 4.t+t+/+>.5+[.u+m s.s.G W.G x.x.W.2 P.s X e.x+~ r.G x+x+s.m ~+F _ ) ",
+" 6 6 q S.6 d.d.6 6 _.R g s+p p.J D H 2.! R.@.4.V.V.B >.w+[.w+%.u+m s.s.x+G i x.x.x+4+&+]+i+2 f Q.} s.$+Q.$+u+^ /+ ",
+" S.q 6 3.J.C # & K B.$ (.+./ D D j+H.@.R.R.4.4.,.t+t+>.w+[.[.$+~+s.s.P G x.x.x.x.r.f <+K : g I.] c !.)+u+u+_ ",
+" 6 3.-++ p+d p+p+:.(.; d.| }.J H t }.t Q 4.4.Q o+z.o+/+5+A+G.I G.~+P ( ( ( ( x.~ $.$.G.- N.y &.v ,+v ;+[.$+5 ",
+" . 6 % C a.J.; 6 3.| | | }.J D t t t t @.4.Q Q o+o+B w+o+G.I E.u+s.( g.%+$.r.x.$.%+( E.W.Q.- b.3 3 !._ [. ",
+" 6 6 6 6 6 6 3.3.9+5.J J D D (+=+H @.@.a 4.t+t+t+5+>.[.w+u+u+s.$+s.W.x+x+G x.x.x.x.x.x.i x+Q.^ ^ ^ _ ",
+" . 7+-+-+S.6 v.9+3.-.-.9+y+{.D+J J J @.a D D 4 H /+>.! @.@.@.m $+4.4.4.t+x+x+B B B ) G x+V.V.s.$+$+@+ ",
+" . 6 6 q q q v.e D+5.J v+y+(+=+H @.@.R.4.V.u V.t+/+_ w+[.u+$+~+Q.s.P s.P x+x+x+x+x+x+x+P P Q.$+5 ",
+" . 7+-+-+v.q 9+e 5.J / y+{.=+=+H @.@.q+B+t+V.V.t+B w+5+w+u+%.u+Q.s.s.P s.P P W.P P s.$+$+u+) ",
+" . 6 6 q 3.v.e e 5.J v+/ {.H =+H @.a 4.4.V.t+0 b+B _ w+w+u+$+m $+s.s.s.s.s.P s.Q.Q.Q.u+5 ",
+" . 7+q v.9+e e 5.J D D D H =+H ! @.@.4.4.t+V.B 5+/+_ w+w+[.u+u+u+$+s.s.u+s.m ~+u+u+@+ ",
+" 6 -+v.9+D+`.J J / D (+H 2.H.@.a 4.4.z+t+t+t+/+5+5+[.[.w+[.[.u+u+u+$+u+$+u+[. ",
+" . -+v.9+e 5.J J y+{.{.H H.! @.a R.4.4.V.V.t+/+B _ w+w+[.[.[.[.u+[.u+[./+ ",
+" 3.e 9+e J / / D (+=+=+@.H @.4.4.V.u t+B t+@+B /+/+w+w+w+[.w+_ /+ ",
+" -+O.e e J / y+{.D 4 @.@.2.@.q+a 4.4.V.V.t+B /+B /+/+_ 5+/+) ",
+" -.5.J / / j+(+(+=+! H.@.4.4.4.4.t+t+t+t+@+B t+4. ",
+" O.O.J D 4 j+=+=+2.@.@.4.4.4.4.4.V.V.@.a ",
+" / {.4 H H H 2.=+@.@.a 4. "};
diff --git a/arts/builder/pics/Synth_SEQUENCE.xpm b/arts/builder/pics/Synth_SEQUENCE.xpm
new file mode 100644
index 00000000..23caeb2f
--- /dev/null
+++ b/arts/builder/pics/Synth_SEQUENCE.xpm
@@ -0,0 +1,319 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 248 2",
+/* colors */
+" c #354280",
+" . c #303C7B",
+" X c #3F4C8D",
+" o c #695B5D",
+" O c #313972",
+" + c #3A4688",
+" @ c #313468",
+" # c #263071",
+" $ c #354283",
+" % c #838594",
+" & c #334081",
+" * c #323E80",
+" = c #1E2869",
+" - c #F4BE22",
+" ; c #EEE45E",
+" : c #1C2667",
+" > c #293477",
+" , c #283276",
+" < c #8C93B7",
+" 1 c #4D588D",
+" 2 c #212C6F",
+" 3 c #1E286C",
+" 4 c #515B9E",
+" 5 c #4E599B",
+" 6 c #3C4986",
+" 7 c #1A235E",
+" 8 c #4B5598",
+" 9 c #374581",
+" 0 c #364380",
+" q c #4E4A66",
+" w c #DCD48E",
+" e c #47548A",
+" r c #6772B0",
+" t c #212B68",
+" y c #404D8D",
+" u c #7A7D91",
+" i c #2D3977",
+" p c #535D8F",
+" a c #3A4787",
+" s c #293373",
+" d c #FBE73F",
+" f c #273171",
+" g c #A2A7C2",
+" h c #252F6F",
+" j c #38427B",
+" k c #8C653C",
+" l c #4D5C96",
+" z c #7B83AC",
+" x c #252F72",
+" c c #38447E",
+" v c #5F6A97",
+" b c #CAC07F",
+" n c #737BA4",
+" m c #313B81",
+" M c #333E79",
+" N c #1F296C",
+" B c #42508B",
+" V c #3C406E",
+" C c #1E296B",
+" Z c #1D276A",
+" A c #1C2769",
+" S c #303A76",
+" D c #C99732",
+" F c #293379",
+" G c #2C3672",
+" H c #283378",
+" J c #273177",
+" K c #242F74",
+" L c #374480",
+" P c #232D73",
+" I c #747DA8",
+" U c #212B71",
+" Y c #202B70",
+" T c #1E296E",
+" R c #A27D47",
+" E c #465188",
+" W c #404E8C",
+" Q c #303C79",
+" ! c #576292",
+" ~ c #3E4C8A",
+" ^ c #474E7F",
+" / c #A7ACC6",
+" ( c #2B3674",
+" ) c #9B9182",
+" _ c #7B82A8",
+" ` c #283271",
+" ' c #252E6E",
+" ] c #303C7C",
+" [ c #868BAC",
+" { c #2B3677",
+" } c #1B2464",
+" | c #606BAB",
+". c #C1A851",
+".. c #9097B9",
+".X c #666F9D",
+".o c #283474",
+".O c #3C4781",
+".+ c #374486",
+".@ c #656A92",
+".# c #212C6D",
+".$ c #202A6C",
+".% c #384073",
+".& c #1E286A",
+".* c #6B75A5",
+".= c #2D387C",
+".- c #1C2668",
+".; c #947449",
+".: c #4A5995",
+".> c #3A4782",
+"., c #263275",
+".< c #666E96",
+".1 c #485793",
+".2 c #475592",
+".3 c #465591",
+".4 c #222C71",
+".5 c #202A6F",
+".6 c #5A4B52",
+".7 c #333F7B",
+".8 c #1F2A6E",
+".9 c #1E286D",
+".0 c #1D286C",
+".q c #434E84",
+".w c #3F498A",
+".e c #31386F",
+".r c #5C67AD",
+".t c #384583",
+".y c #3A447B",
+".u c #333F7E",
+".i c #2E3B79",
+".p c #333C74",
+".a c #434B7D",
+".s c #F7B618",
+".d c #3A4588",
+".f c None",
+".g c #263171",
+".h c #364184",
+".j c #252F70",
+".k c #242F6F",
+".l c #484664",
+".z c #212B6C",
+".x c #5D6693",
+".c c #303B7E",
+".v c #1F296A",
+".b c #2D397B",
+".n c #1D2768",
+".m c #404C87",
+".M c #989AAF",
+".N c #4E5B8E",
+".B c #252F73",
+".V c #29306D",
+".C c #45548F",
+".Z c #35407C",
+".A c #212B6F",
+".S c #44528E",
+".D c #2F3980",
+".F c #E9A317",
+".G c #1D276B",
+".H c #404E8A",
+".J c #3E4C88",
+".K c #5A515E",
+".L c #9BA1C2",
+".P c #33407D",
+".I c #323E7C",
+".U c #313E7B",
+".Y c #424264",
+".T c #F5D836",
+".R c #656FAE",
+".E c #1D2664",
+".W c #3C4A89",
+".Q c #2C3876",
+".! c #2B3675",
+".~ c #384685",
+".^ c #465296",
+"./ c #5863A1",
+".( c #434E93",
+".) c #323C7F",
+"._ c #303A7D",
+".` c #9C9FB2",
+".' c #8E8E97",
+".] c #3C4982",
+".[ c #374287",
+".{ c #364286",
+".} c #354085",
+".| c #232E70",
+"X c #171F57",
+"X. c #46558F",
+"XX c #43518C",
+"Xo c #1E286B",
+"XO c #1C2669",
+"X+ c #2B367B",
+"X@ c #6A554F",
+"X# c #263076",
+"X$ c #9096B3",
+"X% c #253075",
+"X& c #242E74",
+"X* c #232E73",
+"X= c #36417F",
+"X- c #212C71",
+"X; c #202A70",
+"X: c #43518F",
+"X> c #B6AD96",
+"X, c #8289AF",
+"X< c #3D4B89",
+"X1 c #414C83",
+"X2 c #2A3573",
+"X3 c #414979",
+"X4 c #283371",
+"X5 c #B8BCD0",
+"X6 c #BD8933",
+"X7 c #575B7E",
+"X8 c #5B6799",
+"X9 c #7F87AF",
+"X0 c #3C478B",
+"Xq c #7D85AD",
+"Xw c #283374",
+"Xe c #39467E",
+"Xr c #F8AF10",
+"Xt c #343F83",
+"Xy c #232D6F",
+"Xu c #222D6E",
+"Xi c #333D82",
+"Xp c #212B6D",
+"Xa c #303D7F",
+"Xs c #54609F",
+"Xd c #2E3B7D",
+"Xf c #775F51",
+"Xg c #424E8A",
+"Xh c #1D2769",
+"Xj c #515E9C",
+"Xk c #58556E",
+"Xl c #2C377B",
+"Xz c #2A3579",
+"Xx c #293578",
+"Xc c #40477E",
+"Xv c #757487",
+"Xb c #222D71",
+"Xn c #8890B4",
+"Xm c #455490",
+"XM c #878EB3",
+"XN c #6E78AB",
+"XB c #4D5684",
+"XV c #1F296E",
+"XC c #1E296D",
+"XZ c #41508C",
+"XA c #4A5281",
+"XS c #69719C",
+"XD c #3B4886",
+"XF c #5B6081",
+/* pixels */
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f # , > F HX# KX&.4.8 C.n.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f G.I.[.}Xi.D.=X+ F JX% K P.4X- YX;XV } 7.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f 6.(.(X0.[.}Xi.D.=X+ F JX% K P.4X- Y.5.8XV TXo 7.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.fX= 4 5 8.(.(X0.[.}Xi.D.=X+ H JX%X& P.4X- Y.5.8XVXC.9.9 3XO 7.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f./.r 4 5 8.( XX0.[.} m.D.=X+ H JX%X& P.4 U Y.5.8XVXC.9 3 3.0.G.-.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f 5 |.r./ 4 5.^.( XX0.[.} m.D.=X+ H JX%X& P.4 U Y.5XVXVXC.9 3 3.G.G.GXO 7.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f r r.r.rXs 4 8.^.( XX0.[Xi._.bX+ F H JX%X& P.4 YX;.5XVXVXC.9 3 3.G.G.G Z Z :.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f E r r.R.r.rXs 4 8.^.(X0.d.[.) M.i { H HX#X%X*XbX- Y.5.8XVXV.9 3 3.0.G.G Z Z Z Z.-X .f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f 1 r r.R.r.rXs 4 8.^.( XX0.[.}.%Xk V OXw JX# KX*XbX- Y.5.8XVXC.9 3 3.G.G.G Z Z ZXhXO :X .f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f l r r r.R.r./Xs 4 8.^.( XX0.{XtXk R o VX4 JX%X& P.4 U Y.5.8XVXC.9 3 3.G.G.G Z Z ZXhXOXO :X .f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f 1 r r r.R.R r.R |./Xs.2 XX0.d.h LXF. o.p.Q JX%X& P.4.A.8XVXoXo.GXo 3.G.G.G Z Z ZXh AXOXO.- :X .f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f E r r r.R |XN < <XnX9XN l.w.d.[.h.]Xv. o O.bX#X%X*XbX- YXV.v.v.v Z N 3 3Xo.G.G Z Z ZXhXhXO.-.- :X .f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f r r r.R.R z < / g.L..X,.X.N.w.{.t e u bXk ( {X% K P.4X- x f O.%.e.V h N 3 3 3XoXoXoXo.& ZXhXh.-.- :.f.f.f.f.f.f.f",
+".f.f.f.f.f.f r r r | | z /X5X5X5X5 /.LXM I 1.h.m ! % bXk.! >X%X& P.4.5 `Xc ! _.x.q G.$.A.8.$.$.$.$.$ N.vXo.&.&Xh.n }.f.f.f.f.f.f",
+".f.f.f.f.f 5 r |.r |XN < /.. _ nXS I z z z 1Xt.q.< % )Xk ,., KX* PXy.#.p v n < n p.p.#Xu 2 2 2.#.#.#XpXp.$.$.v.v.v = 7.f.f.f.f.f",
+".f.f.f.f.f |.r.r.r.*.L /X5 I l.2X: l.XXNX9 1 *XAXS % )Xk.,.BX&X* PXu '.a [.. gX,XS.y.kXy.|.|.|.|XyXyXyXuXu.#Xp.z.$.$ =.f.f.f.f.f",
+".f.f.f.f./.r.r./Xs.*.L.L.L.X.2 y.w.wXg E E c.c.a u % ) ^., x x.|Xb f M p [.. / [.X.y.g x.B x x x x x x.k.|XyXyXu.#.z.$ =.f.f.f.f",
+".f.f.fX=.r./Xs 4 4.* /.L <X8.( XX0.d.[Xt.)._.=X3XvXv uX3 f.B x x x.p pXSXM.L /XM.X.y f #.,.,.,.,.g.g.g x # x.k.kXyXu.#.#.E.f.f.f",
+".f.f.f 4 4 4 4 5 8.X /.LXMXs XX0X0.[XtXi.c.).uXF ).'.'XF.y j.p G `X3XS nXqX$ g [XSXcXw., , >.oXwXwXw.,.,Xw.g.g #.j.kXyXu.$.f.f.f",
+".f.f.f 5 5 5 8.^.^.X /..X9XjX0.d.[.}Xi m._X=Xg _X5 gX$ _.X v.x.a OXBX$Xq nXM.LX,XSXc.! >XzXxXxXx > > >.o.oXwXw f.g #.j.kXy.f.f.f",
+".f.f 6 8 8.^.^.(.(X8 g..XM p.d.h.} m.c.Z.] E p [X5 /.`Xn _ I n.xXAXS.LXM _X$ /X$ _ ^.Q.Q ( (X2X2 (.!.! >.!.o.o.oXw f f.g h.E.f.f",
+".f.f.(.(.(.(.( X.w !.L.. < p L & m.c .X1 v.X.X.`X5X5 g.`..X$ <Xq n < /.. _.LX5.LXMXB Q Q.p O G G G (.Q { { { {.!.o.oXw f.g h.f.f",
+".f G.(.( X X XX0X0 1X9.. g.* e.O.I j.q.xXqXS p.'X> %X7XB ^XAXA p !.*XMXq I..X5 gXM.x.aXk o.K.6.6.6.6.Y @ @ G.Q.!.!.!X2 sX4 f t.f",
+".f.IX0X0X0X0X0.[.[Xg.X <X5.. n 1.Z 1 IXM gXSXA uX>Xk.e G s (.Q.Z E p.XXS n..X5 g < n.@Xv RX6X6X6X6 k kX@.l @.Q.Q i.Q.!.!.oXw t.f",
+".f.[.[.[.[.[.[.}.}X=.q vXMX,XqXS p.< _ n n.xXB uX>XF S.!.!.Q S Q.I cX1.q.q.@ <XM [.' ). D D.F.F.F DX6 kXf.l @ G i.Q.Q.Q.!X2X4.f",
+".f.}.}.}.}.}.}XiXi m.cX1X8 I <XnXMX,Xq v e 1XF uX>XFXlXlXl.=.bXd.b._ ].U M.qXS n _ ). - -.s.s.sXrXrXr DX6X@.Y.e.i.i.i i.Q.!X2.f",
+" #XiXiXi m m m m.D.=.= Q cXc ^ ^.a.aXc j S.aXFXv )X7XlXl.b.=Xd.cXd ].c.I.I j.qXF % ) - - -.s.s.sXrXrXr.F.F k.6.Y Q.i.i.i i.Q.!X4",
+" ,.D.D.D.D.D.D.D.=.=XlXzXz , s f # # # f., VXvXv )XAXl.bXd.c.cXaXa * & & & & XA %. - -.s.s.sXrXrXrXrXrXrX6 k.Y.U ].U Q.i i iX2",
+" >.=.=.=.=.=XlX+X+X+Xz H J.,.g x x # s , ,X3XvXvXvXk.bXd.cXaXa * * &Xt $ $ $ 0Xk.;. - -.s.s.sXrXrXrXrXr.FX6Xf.Y.P.I.I.I Q.i.i.Q",
+" FX+X+X+X+X+Xz F F H H J JX#X#X%.BX%X# , ,Xk )XvXF q.=.cXaXa * & & $ $ $.{.t.t q.;X6 - -.s.s.sXrXrXrXrXr.F RX@.Y .P.P.U Q.i.Q",
+" H F F H H H H H J JX% x.V.V @.V.V @.e G.!Xk )XvXk.lXd.cXa * & & $ $.{.+.+.~.t.K RX6 D D D.F.F.F.F.F.FX6X6Xf.l V $ 0 .P.P.I Q.i",
+"X# J J J J J JX#X# K.B.V V.l q q.l V.p O GXk. oX3 V.cXa * & & $ $.{.+.~ +XD.>.KX6 R R R RX6.F.F.F.F D RXf.K V j.t 9 0X=.P.P.U.i",
+" KX%X%X%X%X%X%X&X&.V @ q oXf.;.;.;.; o oXk.; bXv ^.y ].).u & $ $.{.+.~ + +.].O.KX6Xf.K.K.K oX@XfXfXfXf.K q V.y L.~.t 9 0 .P.I Q",
+"X& K KX&X&X&X& PX* @.K.;. . ; ; ; ; ;. ). b % E c.I.u.u $ $.{.+ + + +.WX1Xc oX6 oX3.a.mXcX3X3X3X3 qX3.O.] 6 6XD.~.t 9 0X=.P.U",
+".4 P P P P P P 2 '.Y.;. . .T d d d ; ; ;. b w.'.x 1.qX1X1.].~.~.~ + +.W.W.qX3 oX6 o.aX1.H.mX1X1X3.a.a.] 6.J ~X< 6XD.~.t 9 0.P.I",
+".8.4.4.4.4.4.4.z t.6. . .T d d d d d d ; ; w w.` I n.*.XX8.q L L.~ +.W.W X ^X3 oX6 o.qXgX:XZ.H.H.m.m.H.H W W.H.JX< 6XD.~.t L .7",
+" CX-X-X- U U Y.$ t.6. -.T d d d d d d ; ; w w /XMXMX,X,XM v E.O.~ a.W X X ^ q o R.K B.SX..N p p p.N 1.q.H.H W.H.JX< 6XD.t.t 0.Z",
+".n Y Y Y Y YX; t.VX@ D -.T.T d d d d d ; ; wX5X5.L.L.L /X5.. n e.>XD X X yX3XkXf.;Xk.S 1X8 nXnXnXnX, _ p B.HXZXZ.H.J.W 6.>.> L.P",
+".fX;.5.5.5.5.5.v t.Y.;X6.T.T.T.T.T.T.T ; w wX5 % p p.NXSXM <...< E 6 ~ W yX3.KXf kXk.C pXNXqXn n.< nX$XS.NXXXZXZ.H.H.J 6XD.t 9.f",
+".fXV.8.8.8XVXV 3.v @.6.; D -.T.T.T.T.T ; wX> /XF.p M.Z.q v <X5XnX8 E ~ WX:X3 oXfXfXk.2X8XMXMXM.< 1XS gX,.X 1XXXZXZ.H.J.J 6.> L.f",
+".f }XVXVXVXVXV 3.G t @.6 k RX6 D D. . bX>.`.`X7 SX=.t.m EXSX5Xn.X e ~.HXZ qXfXfX@X7.2 ! I I I v.NXS /Xn.*.N.SXXXXXZ.H.J 6XD.p.f",
+".f 7 TXCXCXCXC.9.9.n t @.Y.6Xf.; R R R )X$X$X$XA S 0 $XD c p.LXn I.N.H.HXZ q kXf.KXA.1 !.*.*.*X8.NXS /.. I.N.S.S.SXZ.H.J 6 6 M.f",
+".f.fXo.9.9.9.9 3 3 Z.n.V.% V.Y.Y.l qXk.@ _ [X$XA Q 0 $XD L p.L <Xq v 1.N.NXv RXvXv.x lXjX8X8.*.*XS [X5.. I p.C.S.SXXXZ.H.J.>.f.f",
+".f.f 7.9 3 3 3 3 3 3.G 3 3.8.AXy # s SXAXSXq..XA Q 0 $XD 9 p.L..X, I.* I z.M b ).' _.*X8 lX8.*Xq.. /X5.L z pX..S.SX:XZ.H.J j.f.f",
+".f.f.f 3 3 3 3.0.G.G.GXo 3.8 2Xb x f (X1XS zX$XA Q.u $.t c ! g..X9 z IX, <.` bX>.MX, IX8 lXjX8X8.<Xq /..Xn !X..CXm.SXZ.H.J.f.f.f",
+".f.f.fXO.0.G.G.G.G.G.G.G 3.$ 2.| x.g.oXcXS zX$XA S.I &X= c.x /..XqXqX9...LX5 wX5 /.. zX8 l l l l p.X <...L ! e.SXm.SXZ.H 6.f.f.f",
+".f.f.f 7.G.G.G.G.G.G Z.GXo.$ 2.| x.g sXcXSXq..XB.p M.ZXeXB n / n p p p v u ) b.' n.<X8X8 v v v ! pXS.L.... ! e.SXm.SXZ.HXe.f.f.f",
+".f.f.f.f.-.G.G Z Z Z Z ZXo.$.#.| x.g sXc.XXq..XB.p M jXB _X$ /.xX1.m B eXFXv. Xv p.N.NX8X,X9X9.X !XS g.L.. ! e.SXm.SXZ.m.f.f.f.f",
+".f.f.f.f.fXO Z Z Z Z Z ZXo.$.#Xy x #Xw j.x nX$.<XBXBXB.@Xq _XqXB.].J.H ^X7Xf R o 1.: lX8 IX9Xn _XSXq.LXn I pX..C.CXX.H.f.f.f.f.f",
+".f.f.f.f.f 7 Z Z Z ZXh ZXo.$.#Xy x xX4 M 1XSX$ [ [ [ [X,X,.* !.q.W.HXZX3 qX@ k.K.1.: lXj.X z....X$.... _.X.N.2.C.CXX.O.f.f.f.f.f",
+".f.f.f.f.f.f : ZXhXh AXh.& NXpXy x.gXw S.p.y ^ ^ ^ ^ ^XAXA.q.m.m ~ ~ WX3.KX@ k q.1.: lXjXjX8 v v v v v ! l.1.3.C.S.H.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.-XOXOXOXh Z.vXpXu.k x.,.!X2 ( G.Q S Q M.7.Z L.~.WX< ~.H V.6X@ k q.1.:.: l l l l l l.:.:.:.1.2.2.C B.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.fX :XOXOXOXhXo.$Xu.| #Xw.o.! i Q.I.PX= 0 L.t.~ a 6.W.J ~.lX@X@X@ q.2.1.:.: l l l l l l l.:.2.3XmXX.y.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.fX :.-.-Xh.&.$.#Xy x.gXw.o { i.i ].I.u $.t.~XD.WX<.J.l kX@.6X3Xm.1.1.:.:.:.:.:.:.:.:.1.2XmXX.y.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.fX :.-.-.&.vXpXy.k.gXw.o { i.i ..I.u & .t.t.~XD 6 6 q kX@.6X3Xm.3.2.1.1.:.:.:.1.1.2.2XmXX.y.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.fX :.-Xh.v.zXu.k # f.o.!.Q i.i ].I.u $.t.~ a.>.>.6 kX@.lX3.SXmXm.3.2.2.2.2.2.3.3.CXX.y.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.fX :.n.v.$.#Xy.j.gXw.o.! i.i ..I.u.u $.t.~.t.>.l k.6 VXcXX.S.S.SXmXmXmXm.C.C.S B.y.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f } =.$.zXu.k # f.o.!.Q i.i ..I.u 0 9.t 9 c.YX@.l.y.]XZXZXXX:.S.S.S.SXXXX.H.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f 7 =.$.#Xy.j fXwX2.!.Q.i.i.U.I.P 0 9 L L.%.Y VXe.].H.HXZXZXZXZXZXZ.H.O.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f =.#Xu.k.g f s.!.Q i.i Q.I.P.PX= 0 0 L 9.>.>.] 6.J.J.H.H.H.H.H.m.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.E.$Xy h.gX4.o.!.Q i.i Q.U.P.P 0 L 9.>.> 6 6 6.J.J.J 6Xe.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.E h fXwX2.!.Q i.i Q.I.P.PX= 0 L.t.>.t.>XD 6.> j.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f t tX4X2.! i.i.i Q.U.I.P.P 0 L 9 L.p M.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f",
+".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.fX4X2.Q.Q.i.i Q.U.I.7.Z.P.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f"
+};
diff --git a/arts/builder/pics/Synth_SEQUENCE_FREQ.png b/arts/builder/pics/Synth_SEQUENCE_FREQ.png
new file mode 100644
index 00000000..ebd9d829
--- /dev/null
+++ b/arts/builder/pics/Synth_SEQUENCE_FREQ.png
Binary files differ
diff --git a/arts/builder/pics/Synth_SHELVE_CUTOFF.xpm b/arts/builder/pics/Synth_SHELVE_CUTOFF.xpm
new file mode 100644
index 00000000..bbee7585
--- /dev/null
+++ b/arts/builder/pics/Synth_SHELVE_CUTOFF.xpm
@@ -0,0 +1,247 @@
+/* XPM */
+static char * Synth_SHELF_CUTOFF_xpm[] = {
+"64 64 180 2",
+" c None",
+". c #161E54",
+"+ c #4A9A2C",
+"@ c #4A5A94",
+"# c #2E3E7C",
+"$ c #62CA2C",
+"% c #4A8644",
+"& c #3E4E84",
+"* c #66E614",
+"= c #52AE2C",
+"- c #222E64",
+"; c #364684",
+"> c #46725C",
+", c #8692B4",
+"' c #6E769C",
+") c #52629C",
+"! c #4A529C",
+"~ c #6EF614",
+"{ c #2A3674",
+"] c #7E86AC",
+"^ c #363E84",
+"/ c #62DA14",
+"( c #46568C",
+"_ c #3E4684",
+": c #969ECC",
+"< c #1A2664",
+"[ c #52A62C",
+"} c #424E94",
+"| c #767EA4",
+"1 c #525A94",
+"2 c #222E74",
+"3 c #62D224",
+"4 c #6AEE14",
+"5 c #8E9ABC",
+"6 c #5A62AC",
+"7 c #7EFE1C",
+"8 c #323A84",
+"9 c #56BE1C",
+"0 c #3A4A7C",
+"a c #6E7ABC",
+"b c #2E3A74",
+"c c #868EB4",
+"d c #36427C",
+"e c #222A64",
+"f c #5A9E44",
+"g c #4E5E94",
+"h c #32427C",
+"i c #464E8C",
+"j c #6EE624",
+"k c #5E6AB4",
+"l c #8E92C4",
+"m c #52669C",
+"n c #72FE14",
+"o c #3E4A84",
+"p c #2A3274",
+"q c #36428C",
+"r c #767AA4",
+"s c #4A5694",
+"t c #56A644",
+"u c #425294",
+"v c #66D224",
+"w c #6672BC",
+"x c #162254",
+"y c #4E5AA4",
+"z c #323E84",
+"A c #62CE24",
+"B c #42528C",
+"C c #6AEA14",
+"D c #56BA1C",
+"E c #26326C",
+"F c #3A468C",
+"G c #727AA4",
+"H c #2E3674",
+"I c #7E8AB4",
+"J c #62E214",
+"K c #1E2A6C",
+"L c #7E82B4",
+"M c #525EA4",
+"N c #263274",
+"O c #3A427C",
+"P c #666EB4",
+"Q c #7AFE14",
+"R c #3E4A94",
+"S c #4E5694",
+"T c #52A22C",
+"U c #4E5A9C",
+"V c #323E74",
+"W c #424E8C",
+"X c #262E6C",
+"Y c #3A467C",
+"Z c #8A96BC",
+"` c #7276A4",
+" . c #5662AC",
+".. c #9AA2CC",
+"+. c #1E2664",
+"@. c #7A82AC",
+"#. c #6AF214",
+"$. c #929AC4",
+"%. c #5A66AC",
+"&. c #86FE1C",
+"*. c #6EC644",
+"=. c #3A4A8C",
+"-. c #2E3A84",
+";. c #8A8EBC",
+">. c #222A74",
+",. c #56A24C",
+"'. c #626EB4",
+"). c #8E96BC",
+"!. c #5666A4",
+"~. c #56AA44",
+"{. c #465294",
+"]. c #66D62C",
+"^. c #1A2264",
+"/. c #4E9E2C",
+"(. c #4A5A9C",
+"_. c #62CA34",
+":. c #6A76BC",
+"<. c #3E4E8C",
+"[. c #6AE624",
+"}. c #56AE34",
+"|. c #222E6C",
+"1. c #8A92BC",
+"2. c #6E76A4",
+"3. c #5662A4",
+"4. c #72FA14",
+"5. c #2A367C",
+"6. c #7E86B4",
+"7. c #62DE14",
+"8. c #465694",
+"9. c #5EC22C",
+"0. c #5ED614",
+"a. c #52AA2C",
+"b. c #46528C",
+"c. c #6EEA24",
+"d. c #5ABA2C",
+"e. c #525AA4",
+"f. c #6AEA24",
+"g. c #1A225C",
+"h. c #5AA244",
+"i. c #9A9ECC",
+"j. c #464E94",
+"k. c #262E74",
+"l. c #82FE1C",
+"m. c #626AB4",
+"n. c #76FE14",
+"o. c #3A428C",
+"p. c #5AA644",
+"q. c #6AD224",
+"r. c #66CE24",
+"s. c #828AB4",
+"t. c #66E214",
+"u. c #565EA4",
+"v. c #424A94",
+"w. c #6EF214",
+"x. c #5E66AC",
+"y. c #3E468C",
+"z. c #767EAC",
+"A. c #8E9AC4",
+"B. c #3A4A84",
+"C. c #6E7AC4",
+"D. c #2E3A7C",
+"E. c #868EBC",
+"F. c #364284",
+"G. c #222A6C",
+"H. c #4E5E9C",
+"I. c #324284",
+"J. c #5266A4",
+"K. c #3E4A8C",
+"L. c #2A327C",
+"M. c #4A569C",
+"N. c #2E367C",
+"O. c #26327C",
+"P. c #3A4284",
+"Q. c #7AFE1C",
+"R. c #4E569C",
+"S. c #323E7C",
+"T. c #3A4684",
+"U. c #1E266C",
+"V. c #8E96C4",
+"W. c #46529C",
+" N p p L.L.N k.2 >.G.K +. ",
+" e b F.F.8 -.D.5.O.k.N k.2 2 G.2 ^.. . . ",
+" H o v.y.o.F.z -.N.N.5.O.N k.>.2 K K K U.^.^.. . ",
+" b U R.s j.v.F q ^ 8 -.D.5.O.k.2 2 2 >.2 2 >.K K < ^.. . . . ",
+" 1 u.M R.! } R F q I.8 N.5.5.5.L.N k.2 >.K K K K >.K K U.U.^.. . ",
+" S m.x. .e.R.{.} v.y.q ^ z -.N.L.N N k.2 |.2 >.>.>.U.K K U.K U.K ^.. . . ",
+" '.'.k 6 u.y M.j.v.y.F q z 8 -.N.L.O.O.k.k.>.|.K K >.U.K K U.K U.K U.< ^.. . ",
+" i :.w m.%. .M y M.W.R =.o.^ 8 # D.5.5.p N N 2 2 >.2 >.K >.U.U.K U.K U.U.U.U.^.. . . ",
+" O 2.w w m.%.3.e.M.! j.v.y.F F.8 -.D.5.O.O.k.2 k.2 >.|.>.K K K U.K U.U.< U.U.< U.^.. . . ",
+" S a w w m.%.6 M U M.{.} K.F q ^ z N.5.L.L.k.O.k.2 G.>.K K K K K K U.K K K U.K K U.K ^.. . . ",
+" O 2.:.P '.k %.u.e.R.W.} R y.o.q z z -.N.{ L.k.k.2 2 |.>.2 >.K K U.>.U.U.U.K < U.K < U.< ^.. . . ",
+" i :.w w P k %.u.M y M.W.} R F F.z z D.N.5.L.N N N k.2 K >.K K U.U.K U.K K U.U.U.< U.U.K U.U.^.. . . ",
+" w :.P '.x.%. .M y M.{.j.v.K.F q z 8 D.D.5.5.O.2 2 2 2 2 K K K >.K K U.U.K K K K U.K U.< U.< < ^.. . ",
+" w w P ..i.%.6 M y M.! j.<.K.o.q ^ 8 -.-.5.5.N k.k.k.>.>.K >.>.>.K >.K K K K K K K K K K K K U.U.K ^.. . ",
+" o P P m.: : u.M e.R.W.j.v.y.F o.F.^ 8 N.5.L.L.N N 2 k.X 2 2 2 2 2 K 2 2 2 2 K >.>.2 >.2 2 >.2 K K K K < ^.. ",
+" m.m.%.%. .M M e.M.! W.} v.=.F F.^ z D.D.5.5.N O.k.k.2 2 >.>.K |.>.2 2 2 2 2 2 2 2 2 |.G.G.|.G.2 G.>.G.K . . ",
+" S %.6 . .u.y y R.8.j.} R y.F o.z z 8 N.N.5.L.N O.N 2 2 k.2 N 2 N k.2 2 2 k.N N N X N N N 2 N |.2 |.|.>.|.K < . ",
+" ^ 6 u.) y.e.V.V.M.W.j.} R R F o.z ^ D.D.D.5.N N N k.2 N k.N N k.k.2 N N N N N k.N N N N N k.N k.N E k.2 X 2 G.G.g.. ",
+" i M e.y F M.l 1.W.} v.R F o.q q z 8 -.5.5.5.L.O.N N k.N N N N N p N p N p N { N N 5.N N { N { N N N E N X N E |.G.< ",
+" y R.R.R.P.! , E.} v.R y.o.q ^ z 8 -.N.N.L.L.N p O.p N N N N O.O.N N O.{ { 5.O.5.{ p 5.{ N { N p p { p N N k.k.|.E g. ",
+" H ! W.W.j.^ j.E.s.R y.o.F P.^ 8 # 8 D.5.5.p L.N N O.5.p L.L.{ { 5.5.{ 5.5.{ D.H 5.D.{ 5.D.5.b 5.5.{ 5.{ { { N p X p |.< ",
+" j.u } } } <.R y.y.F ; o.^ z z S.-.D.5.5.p O.{ L.L.N N 5.N { L.5.{ N.N.N.5.N.5.D.D.5.D.D.5.D.5.b D.{ { { { { { { { E - . ",
+" +.v.v.R R y.y.y.y.o.o.F.^ z z 8 N.5.N.5.L.{ O.N p 5.5.N 5.L.5.{ 5.D.D.D.D.D.D.D.D.# D.D.S.D.# D.D.D.D.D.N.5.{ { { { p { E +. ",
+" b F F y.o.F -.F 6.6.^ z z z -.N.D.N.L.p { O.p L.5.5.p 5.5.b D.5.D.D.5.D.D.D.D.D.D.8 # # D.# 8 # D.# D.D.D.b D.{ 5.{ { p - . ",
+" ^ P.q o.q ^ 5.I.6.6.z 8 8 N.-.N.5.5.O.O.N L.{ N L.5.5.5.5.5.D.D.D.# D.# # # z S.# z S.h S.S.S.S.S.S.S.# S.D.8 b H { { H p E ",
+" ^ q ^ I.^ z L.8 L @.-.D.5.D.5.L.5.N p p L.{ O.5.5.{ N.D.5.D.D.D.D.D.# S.z z S.z F.^ ^ z ^ I.z I.S.z S.S.# S.# D.# D.b { { p ",
+"N z z 8 z z 8 p D.z.@.-.N.5.5.5.N L.O.N N O.{ { 5.5.5.{ D.D.D.-.D.z 8 z S.^ I.d z h I.F.F.F.d F.F.d I.F.^ S.S.S.D.S.D.b b b b { ",
+"N D.-.-.N.-.D.D.-.D.N.5.5.L.p N L.N N O.5.p L.5.5.5.D.D.D.D.D.D.z S.h z z I.F.F.; F.; ; ; F.; F.F.F.F.d I.d F.d h S.S.S.D.b { { ",
+"L.N.N.-.N.5.5.5.L.L.p 5.O.O.N k.k.k.k.N O.{ p 5.b 5.D.D.-.# z S.z z I.d F.F.F.F.T.P.P.; T.T.T.T.; T.; T.F.F.I.^ S.S.S.# D.b b H ",
+"N 5.5.L.5.5.L.|.5.| z.N N N k.N N N N N { O.5.5.5.D.D.D.8 8 # z z F.F.F.F.F.; T.; ; =.T.T.F F ; T.T.F ; ; ; O ; F.F.S.S.S.S.D.D.",
+"p L.5.N L.5.L.>.O.r r > h.p.,.,.,.h.,.h.p.t p.t t t ~.~.~.~.~.}.~.~.,.; ; ; ; F =.T.y.=.B.B.K.=.=.T.T.T.T.; F.; d F.d h S.# D.b ",
+"k.N k.O.N k.N G.N G G f &.&.&.l.l.7 7 7 Q Q Q Q Q n.Q n.n.n.n n.n n n [.= F F =.K.=.=.K.K.K.=.K.o =.K.=.B.=.B.T.; ; F.^ h S.S.D.",
+"k.O.k.k.O.2 N G.N G G % v v v v v v 3 r.r.A A A A $ A A 3 j [.c.n n n 4.w.= B.=.K.<.<.<.<.W <.<.<.<.& K.o _ B.T.T.; ; d d h h S.",
+"2 2 2 2 2 k.2 2 2 2 2 2 G.G.G.G.X |.k.N N 5.b D.D.# # S.^ I.F.F.].[.C 4.n w.a.K.<.K.K.<.<.<.W <.W <.v.<.K.<.K.=.T.T.T.P.d ^ ^ D.",
+">.k.k.2 2 >.>.>.2 >.2 2 |.G.|.G.k.N N 5.{ 5.5.D.D.8 # S.^ F.; F.; F =.3 f.~ #.a.W B } } B B } W W B <.<.K.K.& K.o T.B.; ; d d S.",
+"G.2 2 G.>.k.2 K >.G 2.>.K 2 >.2 N k.p N L.5.b D.D.# z I.I.F.F.F F F F K.=.].w.4 = } B B u u b.B u W B B B & v.& =.B.T.T.T.d d S.",
+"U.K 2 |.K >.G.K G.G 2.G.K K |.K N N N { { 5.5.D.D.8 S.z I.F.; T.B.=.=.<.<.<.].#.4 a.{.{.{.8.8.{.8.u u B u B <.W K.=.B.T.T.; ; d ",
+"K >.>.K >.K K U.K ` G K K >.K 2 2 k.N O.5.5.D.D.S.z S.F.; ; q ; F K.<.K.W W u v 4 C a.( 8.{.{.8.{.8.{.u b.B B <.W & K.B.B.T.O S.",
+" K >.K >.>.G.U.K ` 2.U.K >.|.2 N N { N { D.D.D.# z h F.F.T.F B.=.K.<.<.u W u 8.3 4 * a.@ @ 8.@ 8.8.s 8.{.{.b.B W <.K.B.T.; T. ",
+" K K >.K K K K K K G.>.K K >.|.2 k.N { 5.5.D.D.z h ^ F.; ; T.F =.K.<.<.<.u {.u 8.9 C * [ 8.@ 8.s @ 8.8.( u B W W W <.o o T.; ",
+" . +.K K U.K >.U.K K U.K K >.2 N N L.{ { D.D.8 S.z S.F.F.; =.o <.K.} u B B 8.8.M.8.a.* * [ (.@ @ @ @ 8.s 8.8.b.B W <.<.o T.V ",
+" g.K K K K U.< K 2.2.K K G.|.X k.k.N 5.D.5.D.# z h F.F.F F T.=.=.<.B W u 8.{.8.@ (.@ [ * J [ H.U U @ (.@ 8.( 8.B B W o o Y - ",
+" ^.U.K K U.< U.` ` U.K K K 2 N N N p D.D.D.D.z I.F.F.T.=.F o K.K.} B u 8.8.8.8.(.g @ a.* J [ g U g @ @ 8.8.{.B W W <.B._ ",
+" ^.K U.U.K U.K ' ' K U.>.|.2 k.N p 5.{ D.D.S.S.S.F.; ; T.o K.<.<.B } b.8.s M.@ @ (.H.g [ 7.7.[ H.(.(.(.s ( 8.b.B B & & E ",
+" ^.K U.U.+.U.2.` K U.>.G.|.k.N N 5.{ D.D.z z I.F.F.; F =.K.<.<.B u {.{.@ @ (.(.H.H.H.) [ 7.7.[ g U g @ 8.8.8.B W W W ",
+" U.U.K K < K U.< U.K K |.2 N N { p 5.D.D.D.S.^ I.T.F T.B.K.W W } B 8.8.8.8.@ g (.H.H.) ) [ 7./ 9 /.(.@ @ 8.B B B & O ",
+" . ^.< U.U.U.U.< < U.G.|.|.N N { { 5.D.# S.S.^ h F.; F =.=.<.B } B 8.8.@ (.(.g H.) ) m m m d.7.J / D + @ s {.b.W & _ ",
+" U.U.U.< K 2.` K K K G.2 2 N N 5.{ b 8 D.S.I.F.; T.T.B.K.K.<.B u u {.8.8.@ U H.H.H.) ) J.J.A 7.7.7.0.}.8.( B B 0 ",
+" ^.U.^.U.' 2.U.U.K G.X 2 N N { 5.b # # S.S.F.F.; T.B.K.K.<.W b.8.8.@ M.@ (.H.) ) ) ) ) ) M $ A 3 0./ 8.b.b.W ",
+" < U.K U.' ` 2.` K |.` G r | 5.{ z.z.@.@.F.d 6.6.s.s.=.<.c c E.c {.8.Z Z ).Z H.H.A.A.: A.) g 5 Z *.7.b.( B H ",
+" . U.U.' ' ' ` K |.G G r r { H @.L ] @.z d s.I s.s.o K.c c , 1.{.8.Z Z ).Z H.H.$.).5 5 H.g ).5 1.Z b.B W ",
+" < < ^.U.+.K U.K |.N N N p { H { D.S.S.h d F.T.T.F <.<.<.W B B 8.s @ @ U (.g H.g H.H.g (.@ s ( b.( B ",
+" . ^.< < ^.+.U.G.+.K |.|.{ { N E E N z z { { b b T.=.S.S.S.h b.B F.F.; Y (.@ B.T.T.T.@ U ; Y 8.B i Y ",
+" . U.U.< < K K |.|.|.N N { { N.D.S.S.S.d F.; F B.o K.<.W W } 8.b.( 8.8.s @ @ @ @ @ @ @ s 8.( b.{ ",
+" . g.U.U.U.K G.2 2 N N { { D.b D.S.S.d F.; T.; B.=.<.<.B W u u b.8.8.8.8.s s @ @ 8.( ( b.B Y ",
+" . < < U.U.G.G.X k.N N { { D.D.# S.z S.F.F.T.T.o B.<.K.<.B B u b.( 8.s 8.8.8.( ( 8.b.B H ",
+" . g.K K G.K |.X N N { { b D.# S.h d d F.; ; B._ & & K.W B B u b.B ( ( b.{.{.b.B B Y ",
+" ^.K K |.|.N k.p N { 5.H D.# z S.I.F.P.T.F B.F K.<.& W W W B B u B u B B B B ",
+" . U.K G.X E N N { 5.H b D.S.S.h h F.F.T.B.B.B.K.o <.<.<.W W W B B B & Y ",
+" K |.|.2 E p p { b N.b D.S.S.h ^ ; F.F.T.T.B.B.o & v.<.& <.W & o ",
+" g.G.X |.E N N { N.b D.8 V h ^ d ; d T.T.T.B._ B.o o & o o _ ",
+" e E p p { { { b # 8 # V h ^ d F.P.T.T.B.B.B.B.d ",
+" - - { { { H b b # 8 h d d h ; d F.T.V V ",
+" { { { H b # 8 # S.d ^ h "};
diff --git a/arts/builder/pics/Synth_WAVE_SAW.xpm b/arts/builder/pics/Synth_WAVE_SAW.xpm
new file mode 100644
index 00000000..2f515dc4
--- /dev/null
+++ b/arts/builder/pics/Synth_WAVE_SAW.xpm
@@ -0,0 +1,323 @@
+/* XPM */
+static char * WAVE_SAW_xpm[] = {
+"64 64 256 2",
+" c None",
+". c #161E54",
+"+ c #329224",
+"@ c #2A563C",
+"# c #223A54",
+"$ c #36763C",
+"% c #264E44",
+"& c #3EC60C",
+"* c #4A568C",
+"= c #36AE14",
+"- c #323E6C",
+"; c #5E727C",
+"> c #3A4A74",
+", c #36664C",
+"' c #222E64",
+") c #46E20C",
+"! c #5A66AC",
+"~ c #3A566C",
+"{ c #828EB4",
+"] c #3A4A8C",
+"^ c #324274",
+"/ c #7A82A4",
+"( c #369E1C",
+"_ c #4A5E8C",
+": c #42D60C",
+"< c #6E769C",
+"[ c #263664",
+"} c #3ABA14",
+"| c #2E5E44",
+"1 c #32427C",
+"2 c #2A4254",
+"3 c #464E8C",
+"4 c #3ECE0C",
+"5 c #527A5C",
+"6 c #3A427C",
+"7 c #469244",
+"8 c #324A64",
+"9 c #222E74",
+"0 c #2A3A74",
+"a c #4A569C",
+"b c #46AE2C",
+"c c #42A22C",
+"d c #1A2664",
+"e c #32822C",
+"f c #3A526C",
+"g c #565EA4",
+"h c #727E9C",
+"i c #6672BC",
+"j c #52EE14",
+"k c #42528D",
+"l c #3A5E54",
+"m c #32961C",
+"n c #365664",
+"o c #465693",
+"p c #3AA622",
+"q c #4ACE23",
+"r c #3AB214",
+"s c #6A7A94",
+"t c #424A93",
+"u c #2A3678",
+"v c #4EBA34",
+"w c #365264",
+"x c #2A3A66",
+"y c #323A84",
+"z c #66728C",
+"A c #3A4E74",
+"B c #223269",
+"C c #4E5E9C",
+"D c #52D62C",
+"E c #365E54",
+"F c #364683",
+"G c #3A4683",
+"H c #324E64",
+"I c #222A6C",
+"J c #3A8634",
+"K c #3A8E34",
+"L c #2A5A44",
+"M c #46C61C",
+"N c #525A94",
+"O c #3E6E54",
+"P c #626EB4",
+"Q c #425679",
+"R c #3E9E2C",
+"S c #6E7AC0",
+"T c #2A465C",
+"U c #465290",
+"V c #2A3276",
+"W c #525AA4",
+"X c #32862C",
+"Y c #52D226",
+"Z c #26523C",
+"` c #4A5A94",
+" . c #3A6654",
+".. c #52E61C",
+"+. c #3A4674",
+"@. c #7E8AAC",
+"#. c #36A21C",
+"$. c #3EC214",
+"%. c #32624C",
+"&. c #36428C",
+"*. c #2E3E7C",
+"=. c #4A5A9C",
+"-. c #7A7EAC",
+";. c #5AF624",
+">. c #323E7E",
+",. c #4E629C",
+"'. c #3A468C",
+"). c #162254",
+"!. c #2E7E24",
+"~. c #42AA2C",
+"{. c #5E767C",
+"]. c #3A4A84",
+"^. c #626AB4",
+"/. c #3E4E8C",
+"(. c #324664",
+"_. c #767AA4",
+":. c #2A366B",
+"<. c #325E4B",
+"[. c #364282",
+"}. c #469A44",
+"|. c #364A74",
+"1. c #263274",
+"2. c #2E3A84",
+"3. c #4AB62C",
+"4. c #1E2A6C",
+"5. c #425284",
+"6. c #5662AB",
+"7. c #767EAC",
+"8. c #5AF21C",
+"9. c #4EEA14",
+"0. c #56DE24",
+"a. c #46DE0C",
+"b. c #4EC234",
+"c. c #42B624",
+"d. c #3A625C",
+"e. c #465A84",
+"f. c #263E56",
+"g. c #326A44",
+"h. c #5E6AB4",
+"i. c #7E86AC",
+"j. c #727AA3",
+"k. c #527E5C",
+"l. c #42963C",
+"m. c #52F21C",
+"n. c #369A24",
+"o. c #4ED224",
+"p. c #2E3E6C",
+"q. c #6A768C",
+"r. c #52DA24",
+"s. c #3E923C",
+"t. c #46CA1E",
+"u. c #3EAE24",
+"v. c #4AE60C",
+"w. c #3E5A6C",
+"x. c #3EBE14",
+"y. c #3ED20C",
+"z. c #6A76BC",
+"A. c #3A5A64",
+"B. c #3AB614",
+"C. c #424E8E",
+"D. c #36624C",
+"E. c #425A74",
+"F. c #367A3C",
+"G. c #42DA0C",
+"H. c #46B22C",
+"I. c #3A6A54",
+"J. c #2E564C",
+"K. c #42C61C",
+"L. c #3E527C",
+"M. c #3EA62C",
+"N. c #3E4E84",
+"O. c #46529C",
+"P. c #2A524C",
+"Q. c #1A2264",
+"R. c #364674",
+"S. c #2A4264",
+"T. c #3A428C",
+"U. c #222A74",
+"V. c #36922C",
+"W. c #2A4E4C",
+"X. c #4E5694",
+"Y. c #262E6C",
+"Z. c #3E4A8F",
+"`. c #3A9E24",
+" + c #4E5E94",
+".+ c #364A68",
+"++ c #2E3A7B",
+"@+ c #46A22C",
+"#+ c #1E266B",
+"$+ c #368232",
+"%+ c #767E9F",
+"&+ c #369624",
+"*+ c #4ECE24",
+"=+ c #2E3679",
+"-+ c #2E3A6C",
+";+ c #6A7294",
+">+ c #26326B",
+",+ c #525EA3",
+"'+ c #3E4684",
+")+ c #364E66",
+"!+ c #3E8E38",
+"~+ c #2E5A46",
+"{+ c #2E4660",
+"]+ c #368630",
+"^+ c #2A5244",
+"/+ c #56E624",
+"(+ c #828AB4",
+"_+ c #3AA224",
+":+ c #4E5AA3",
+"<+ c #363E83",
+"[+ c #1A225C",
+"}+ c #327E2C",
+"|+ c #627684",
+"1+ c #36466C",
+"2+ c #4A9A3C",
+"3+ c #4EB634",
+"4+ c #5A62AC",
+"5+ c #3E6264",
+"6+ c #567E64",
+"7+ c #4ACA1C",
+"8+ c #42AE2C",
+"9+ c #5E66AC",
+"0+ c #3E566C",
+"a+ c #868EB4",
+"b+ c #3EBA14",
+"c+ c #262E74",
+"d+ c #4E569C",
+"e+ c #3A5664",
+"f+ c #52BA34",
+"g+ c #3E4E74",
+"h+ c #56D62C",
+"i+ c #666EB4",
+"j+ c #42C214",
+"k+ c #52629C",
+"l+ c #3E468C",
+"m+ c #3E4A84",
+"n+ c #465284",
+"o+ c #366A44",
+"p+ c #56F21C",
+"q+ c #42D20C",
+"r+ c #3EB614",
+"s+ c #4A529C",
+"t+ c #2A5644",
+"u+ c #4A5694",
+"v+ c #323E74",
+"w+ c #5E7284",
+"x+ c #3A4A7C",
+"y+ c #222E6C",
+"z+ c #7A82AC",
+"A+ c #369E24",
+"B+ c #26366C",
+"C+ c #2E5E4C",
+"D+ c #324284",
+"E+ c #2A425C",
+"F+ c #464E94",
+"G+ c #42A234",
+" 1.V V V V 1.c+9 U.I 4.#+ ",
+" I ++[.[.y 2.2.u 1.c+1.c+9 9 I y+[+. . . ",
+" =+m+t '+T.[.>.2.=+c+u S %+c+U.9 4.4.4.#+Q.Q.. . ",
+" ++N d+u+F+t '.&.<+y 2.2.c+V 7.j.9 9 U.9 9 U.4.4.d Q.. . . . ",
+" N g g d+s+C.Z.'.&.D+y =+0 9 V _.7.c+9 U.4.4.4.4.U.4.4.#+#+Q.. . ",
+" X.^.9+6.:+d+O.F+t l+&.<+>.2.=+c+1.7.j.9 9 9 U.U.U.#+4.4.#+4.#+4.Q.. . . ",
+" i+P h.4+g :+a F+t l+'.&.>.y 2.u u 1.1.c+c+U.9 4.4.U.#+4.U.#+4.#+4.#+d Q.. . ",
+" 3 z.i ^.! 6.,+:+a O.Z.] T.<+y *.=+u V V c+1.9 y+U.9 U.4.4.#+#+4.#+4.#+#+#+#+Q.. . . ",
+" 6 < i i ^.! 6.W a O.F+t l+'.&.y 2.=+u 9 V S _.c+9 U.9 U.4.4.U.#+4.#+#+d #+#+#+#+Q.. . . ",
+" X.S i i h.! 6.,+:+a O.F+Z.'.&.<+>.2.2.u U.1._.j.9 I U.4.4.4.4.4.4.#+4.4.4.d 4.4.#+4.Q.. . . ",
+" 6 ;+z.i+i+h.! g W d+O.C.Z.'.T.&.>.y =+=+u U.1.j.j.9 y+U.9 4.4.U.#+4.#+d #+4.#+#+4.d #+d Q.. . . ",
+" 3 S z.i i+h.! g ,+:+a O.F+Z.l+&.<+>.2.2.u V 9 c+_.j.9 4.U.4.U.#+#+4.#+4.4.#+d #+d #+#+4.#+#+Q.. . . ",
+" i+i i+P 9+! 6.,+:+a O.F+Z.] '.&.>.2.2.=+u V 1.c+c+9 9 9 U.4.4.U.4.4.#+#+4.4.4.4.#+4.#+#+#+d d Q.. . ",
+" i i i P h.! 4+g W a O.t Z.'.T.&.<+y y u u u 1.1.1.9 U.U.4.4.U.4.U.U.4.U.4.U.4.U.4.4.4.4.4.4.#+#+4.Q.. . ",
+" m+i+^.^.9+! ,+,+:+d+s+U Z.l+'.&.>.<+>.2.u V V 1.U.c+_._.9 9 9 9 9 4.9 9 9 9 4.U.4.9 4.9 9 4.9 4.4.4.4.d Q.. ",
+" ^.^.9+! 6.,+,+:+d+O.C.m+N.l R.<+>.*.2.=+=+u V 1.4.9 j.j.U.U.4.9 U.9 9 9 9 9 9 9 c+9 c+U.I 9 I 9 I U.I 4.. . ",
+" X.! ! 6.g g W :+a s+C.Z.> d.2+E v+y 2.2.u u u c+c+U.c+j._.9 1.9 1.9 9 9 9 c+1.1.1.9 B 1.1.y+1.y+9 y+y+U.y+4.d . ",
+" <+4+6.,+W ,+:+:+a O.C.t f I.7 b.!+, T =+V u 1.1.1.1.9 1.j.7.1.9 c+9 1.1.1.1.1.c+1.1.1.1.1.c+1.c+1.>+c+9 Y.9 I I [+. ",
+" 3 W W :+d+a s+s+F+C.m+m+O v Y 8.*+H.C+x V V 1.V 1.c+c+1.c+1.1.1.V 1.1.1.V 1.B+1.1.u V 1.B+V B+1.1.1.1.1.Y.1.>+y+I d ",
+" :+d+d+a a s+O.C./.'+f O 2+Y 0./+0.*+K C+f.1.c+1.V 1.1.V 1.1.V 1.1.V V u u u V u u V u u V u V V V B+V 1.1.c+c+Y.B [+ ",
+" :.a o s+O.O.C.F+Z.] R.I.3+h+;./+D ..m.t.u.L >+1.9 1.u U.u _.7.u u u u u u u 0 u u 0 u u 0 u 0 u u u u u u B+1.1.c+V y+d ",
+" F+F+F+F+t Z.Z.'.6 )+I.l.D Y *+G+F.R 7+7+t.X L # 1.1.1.9 1.7.7.u u u u u u =+=+2.2.=+++2.=+++=+++++=+u u u u u u :.>+' . ",
+" d Z.Z.Z.Z.l+'.'.F R.I.3+Y 8.Y b g.E+g.u.M j K.p t+[ >+u 9 u 7.7.u 2.++2.2.2.2.++++*.2.++*.++*.++++++++++=+=+=+u u u V :.>+d ",
+" y l+'.'.'.'.&.<+.+ .s.o.Y o.K C+T B+E+L X K.K.K.X t+# >+Y.u z+z+2.0 u ++++++++++y ++*.>.2.*.y *.++*.++++++++0 u =+:.u V Y.. ",
+" <+T.&.&.&.[.1 ^ , 3.Y p+*+b C+:.>+1.B [ L p j+v.$.p t+[ :.u u 0 2.*.2.*.*.*.>.*.>.>.>.1 >.>.>.>.>.>.>.*.*.++++++=+=+u :.V >+ ",
+" D+<+<+<+y y (.%.s.o.o.*+K | 2 B+1.V c+>+# t+X $.$.x.e @ f.:.=+=+y y >.>.>.>.>.<+D+<+>.<+<+D+<+D+>.>.>.>.v+>.v+++*.++++=+:.V ",
+"c+>.>.2.*.++x %.H.*+m.q 8+| [ >+V 1.1.c+1.B B @ _+$.) x.#.Z x j./ *.y >.>.<+D+D+<+D+[.D+[.[.D+[.[.[.1 [.>.<+>.>.++*.++++++x 0 :.",
+"V 2.2.=+=+E+<.K q q 7+K | f.1.c+1.1.V 1.1.>+>+# t+e x.x.x.!.@ ; < ++*.>.>.D+[.[.F [.F F F [.G [.[.[.[.[.[.1 [.1 ^ >.v+*.++++=+u ",
+"V =+2.u V P.M.t.j t.~.L B >+1.c+c+1.1.1.V u u >+[ t+#.x.a.x.( k.w+v+>.&.[.&.[.[.'.&.6 F F F '.F F G F F [.[.[.<+>.>.>.v+y ++++=+",
+"u u c+I ' % M.c.K.X @ # >+y+U.4.U.4.1.1.9 9 U.y+1.f.Z !.x.} } 2+k.E+v+>.&.[.F F F '.] '.'.'.G '.G '.G G F 1 >.1 1 ^ >.>.v+v+++0 ",
+"V 1.V 1.>+W.`._+p t+B ' 9 9 1.9 c+c+1.1.1.u u u 0 0 [ t+#.x.G.} A+L ^ ^ F &.'.'.].'.'+m+].] ].] ].'.'.G G F ^ ^ v+v+1 >.>.>.++++",
+"1.V 7.< < ; t+^+k.; z ;+c+c+j.j.j.j.c+V 7.7.7.7.u u s ; 5 l.} b+} e 5 ; h i.G ] (+{ { (+Z.Z.a+a+{ { ].G %+|+6+5 J.{+-./ i.i.v+++",
+"9 c+7.j.< < B y+z ;+_.j.9 U._.j.j.7.1.V %+7.z+7.2.u z+s q.k.( b+G.} 8+k.q.%+G ] (+(+{ a+/.Z.(+(+(+(+].F s 5 @+c K t+h / i.i.[.v+",
+"9 1.c+c+c+U.9 9 9 c+U.9 U.9 9 U.c+c+c+1.V u u ++++*.*.++++2 L e } } r+e | 8 F G Z./.C./././.k C.C.m+> H ~+e r #.+ J.^ v+[.[.>.++",
+"U.9 U.9 9 U.y+U.9 9 U.9 U.4.9 9 9 1.1.u u u u 2.++2.>.*.>.v+S.k.b } : B.n.@ (.].>.*.>.>.k C.1 >.>.++1+<.m r 4 = m ~+x :.u =+[.>.",
+"4.U.9 U.9 c+U.9 4.4.4.4.y+U.U.9 1.9 1.1.u u ++u 2.>.>.<+D+1 v+{.k.e B.} } X %.8 x+Z.k U U k C.N.N.)+<.e r r r }+~+(.F F G F [.>.",
+"4.U.9 I 4.I I U.U.9 U.4.4.I I U.1.9 1.1.u u ++++++y 1 >.[.[.[.h q.| n.} : B.( <.> m+k k o o U m+.+%.n.r 4 r n.~+(.F G G G F F ^ ",
+"d y+4.4.U.9 4.I I 4.4.4.U.4.9 9 9 1.V u u =+++++>.>.>.[.D+G F / h 8 @ $+B.b+b+]+%.H N.k U C.L.w D.e r+B.r e | )+x+G m+x+G G 6 <+",
+" U.U.4.4.U.4.4.U.U.#+4.4.4.y+c+c+1.1.V u u 2.2.*.>.D+[.[.&.'.].G R.(.<.( B.y.B.`.%.> N.o N.A %.`.r 4 B.n.<..+x+C.m+Z.].G F G ",
+" 4.4.U.4.4.4.4.#+4.U.4.4.U.4.9 9 c+V u u ++++++>.>.<+&.[.G G '.] ].].H <.X b+r+} $+%.n L.e+D.$+r B.B.e <.w m+m+C./.N.m+m+G F ",
+" . 4.#+4.U.4.4.4.4.#+#+#+U.I c+1.1.1.u u 0 2.2.>.>.D+F F F ] (+(+Z.v+].> <.( r+q+b+`.g.f g.A+B.4 r n.D.> L.o k k C./.N.m+G v+ ",
+" [+#+U.#+4.4.4.#+#+4.4.4.4.9 9 9 1.u u u =+++>.*.D+<+&.T.'.G { { /.*.N.].)+%.$+} B.B.V.$ V.r+B.B.J , e+5.U U U k k C.Z.Z.+.' ",
+" ).4.#+#+#+4.4.#+#+4.4.4.y+9 9 c+1.u 2.++++>.>.D+D+F G ] '.(+(+t >.k k N.A D.`.B.q+& x.$.4 r+A+D.L.n+o o o o k k C.N.].'+ ",
+" d #+4.4.4.#+#+4.4.#+#+U.4.c+1.1.1.u u 0 ++2.>.<+[.[.F G Z.a+a+/.<+k k 5.k w D.]+B.x.& x.r+$+D.0+o ` ` ` ` U U C.k N.N.>+ ",
+" Q.#+#+4.4.#+#+d 4.#+I U.9 1.1.V u =+++>.>.1 >.D+[.F G ] Z././.C.k o k o k N.D.A+r+y.r+`. .Q o ` N ` o ` o o k C.C.C. ",
+" #+4.4.#+#+4.4.4.#+4.4.y+Y.9 1.u V u ++++++>.[.[.G '.] G /./.C.k U U o o Q * 0+ .}+p }+I.w.` + +C =.` o o k k 5.N.6 ",
+" . Q.#+#+#+#+#+#+d 4.4.4.c+1.1.B+u u ++*.2.>.D+D+[.[.] G (+{ C.>.k O.O.o o ` 5.Q l J d.e._ k+k+,. +C N ` o U U C.N.'+ ",
+" d 4.4.d #+d 4.4.#+U.y+9 9 1.1.u u u y >.>.<+[.F G G ] a+a+/.D+k o o a ` =.` o Q 5+E._ +k+,.,+C ` ` o o o k k > ",
+" . #+#+#+#+#+4.#+I y+c+9 1.1.u ++0 ++++>.>.[.[.F G ] (+a+C.>.C.U o o o ` N _ ` ` +k+k+k+,.,.C _ ` ` o U n+C. ",
+" d 4.4.4.#+d #+4.4.4.y+Y.1.V u u =+++>.*.[.[.F 6 ] G a+(+/.[.k o o o ` =.=.=.=._ C k+,.k+k+,+ +:+` * U o 5.:. ",
+" . #+d #+d d #+I U.9 c+1.1.V u u ++>.*.>.>.F &.'.'.Z.m+Z.C.C.k o o o ` N _ :+C C k+k+C +C ` N ` o k U C. ",
+" #+d #+#+#+#+4.4.y+y+1.1.B+u ++++++y >.[.D+F G G ].Z././.k k U U o =.=.:+_ C C C C +C ` ` ` o o o 5. ",
+" . Q.d #+d #+4.4.y+y+c+V u u u ++*.*.>.<+[.[.F G { { N.*.C.k k U U o o ` ` _ C =.:+` _ =.u+u+o U C.+. ",
+" ).#+d #+d #+I I 9 1.>+1.1.u u ++y *.>.1 F F F (+(+Z.>.C./.k o o o o a a u+` ` ` ` u+` ` o o 5.:. ",
+" . ).#+#+#+4.I I 9 1.:.u =+=+++y v+>.>.[.G [.(+(+m+*.C.C.C.k k o o o ` o ` ` ` ` o o o U 5.+. ",
+" . d d d 4.I y+Y.c+1.>+u :.++*.*.>.1 [.[.F (+(+].++Z././.C.k U U o U o o o o o o U U 5.:. ",
+" . [+#+4.4.4.y+Y.1.1.u u u ++y y >.1 [.[.F G m+].m+/./.C.C.k k k U U U U U U o Q k '+ ",
+" Q.#+I y+y+9 c+>+u :.=+=+++v+*.>.[.[.[.[.F ].] m+m+/.N./.C.k k k k k k k k C. ",
+" ).#+I y+Y.1.Y.1.u :.0 ++y v+>.>.[.i.i.6 ++].].m+/.N.C.C.C.C.k k k k N.'+ ",
+" 4.I y+Y.1.V B+u u 0 ++y *.1 1 i.(+F ++G ].'.m+m+m+N.N.N.C.C.C.m+ ",
+" d 4.y+B c+V u :.0 0 ++++>.[.z+i.[.u 6 G G G ].Z.m+m+m+m+m+> ",
+" I >+>+V V =+:.++++++*.i.i.[.++F G F G G G ].].^ ",
+" I ' >+=+=+-+++++v+y v+>.>.1 [.F G F >.[. ",
+" V :.=+:.++*.++>.v+<+^ [. "};
diff --git a/arts/builder/pics/Synth_WAVE_SIN.xpm b/arts/builder/pics/Synth_WAVE_SIN.xpm
new file mode 100644
index 00000000..66500375
--- /dev/null
+++ b/arts/builder/pics/Synth_WAVE_SIN.xpm
@@ -0,0 +1,320 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 249 2",
+/* colors */
+" c #6B798A",
+" . c #445292",
+" X c #323E7D",
+" o c #303C7B",
+" O c #3E4C8C",
+" + c #2E3A79",
+" @ c #60C225",
+" # c #2C3877",
+" $ c #2A3675",
+" % c #283473",
+" & c #384486",
+" * c #5B637A",
+" = c #364484",
+" - c #263071",
+" ; c #354283",
+" : c #404B70",
+" > c #334081",
+" , c #838CB5",
+" < c #303C7E",
+" 1 c #4FAD1E",
+" 2 c #818AB3",
+" 3 c #6EE32F",
+" 4 c #72DB33",
+" 5 c #1E2869",
+" 6 c #1C2667",
+" 7 c #66B02E",
+" 8 c #689044",
+" 9 c #374288",
+" 0 c #253073",
+" q c #232E71",
+" w c #343E85",
+" e c #222C70",
+" r c #4FBA17",
+" t c #202A6E",
+" y c #1F2A6D",
+" u c #1E286C",
+" i c #1D286B",
+" p c #2E387F",
+" a c #1A235E",
+" s c #384582",
+" d c #5E8347",
+" f c #435190",
+" g c #333F7D",
+" h c #2F3B79",
+" j c #3E4B8B",
+" k c #606BB3",
+" l c #2E3978",
+" z c #58744B",
+" x c #4E599E",
+" c c #3B4988",
+" v c #2B3775",
+" b c #5C67AF",
+" n c #394786",
+" m c #527245",
+" M c #3A487D",
+" N c #273171",
+" B c #333F80",
+" V c #323F7F",
+" C c #485384",
+" Z c #2F3B7C",
+" A c #2D397A",
+" S c #404C86",
+" D c #2A3577",
+" F c #7A81AB",
+" G c #495892",
+" H c #38447E",
+" J c #202B6D",
+" K c #313B81",
+" L c #1E296B",
+" P c #1D276A",
+" I c #1C2769",
+" U c #2C377C",
+" Y c #293379",
+" T c #283378",
+" R c #4A5A96",
+" E c #263176",
+" W c #242F74",
+" Q c #475693",
+" ! c #232D73",
+" ~ c #455491",
+" ^ c #394378",
+" / c #212B71",
+" ( c #202B70",
+" ) c #42508E",
+" _ c #323C7B",
+" ` c #404E8C",
+" ' c #58D01B",
+" ] c #3A4686",
+" [ c #53C616",
+" { c #364282",
+" } c #25306E",
+" | c #344080",
+". c #242E6D",
+".. c #222C6B",
+".X c #313E7D",
+".o c #424E91",
+".O c #303C7C",
+".+ c #202A69",
+".@ c #2C3878",
+".# c #1B2464",
+".$ c #5BBA21",
+".% c #354284",
+".& c #253071",
+".* c #242E70",
+".= c #334082",
+".- c #232E6F",
+".; c #232C6F",
+".: c #343F79",
+".> c #202A6C",
+"., c #1F2A6B",
+".< c #2C387B",
+".1 c #1C2668",
+".2 c #798881",
+".3 c #688459",
+".4 c #293478",
+".5 c #283477",
+".6 c #2C3571",
+".7 c #283277",
+".8 c #757CA8",
+".9 c #222C71",
+".0 c #212C70",
+".q c #202A6F",
+".w c #1E286D",
+".e c #505B9E",
+".r c #6FD334",
+".t c #475595",
+".y c #364381",
+".u c #509F26",
+".i c #2D3978",
+".p c #3A4788",
+".a c #273372",
+".s c None",
+".d c #344182",
+".f c #48548F",
+".g c #222D6D",
+".h c #2E3B7C",
+".j c #2D397B",
+".k c #3E498F",
+".l c #1D2768",
+".z c #2B3779",
+".x c #4B5374",
+".c c #2F3569",
+".v c #263174",
+".b c #486253",
+".n c #242F72",
+".m c #475691",
+".M c #313D82",
+".N c #43528D",
+".B c #1F296D",
+".V c #42508C",
+".C c #1E296C",
+".Z c #1D276B",
+".A c #404E8A",
+".S c #2C377D",
+".D c #4B5698",
+".F c #495896",
+".G c #6872BB",
+".H c #525C77",
+".J c #41508E",
+".K c #535EA3",
+".L c #303C7A",
+".P c #1D2664",
+".I c #3B4888",
+".U c #2A3474",
+".Y c #48546D",
+".T c #394686",
+".R c #5964AC",
+".E c #526B45",
+".W c #364083",
+".Q c #323E7F",
+".! c #747AA2",
+".~ c #838CB4",
+".^ c #2F3C7C",
+"./ c #2E3A7B",
+".( c #2B3678",
+".) c #3B468B",
+"._ c #283475",
+".` c #263273",
+".' c #47529A",
+".] c #4A6A4A",
+".[ c #242E71",
+".{ c #58B21F",
+".} c #171F57",
+".| c #7F8E88",
+"X c #212C6E",
+"X. c #2E3A7E",
+"XX c #1E286B",
+"Xo c #1C2669",
+"XO c #2B367B",
+"X+ c #2A347A",
+"X@ c #273277",
+"X# c #525B8A",
+"X$ c #253075",
+"X% c #242E74",
+"X& c #232E73",
+"X* c #222C72",
+"X= c #5761A6",
+"X- c #212C71",
+"X; c #445390",
+"X: c #51B41B",
+"X> c #1F2A6F",
+"X, c #434F8F",
+"X< c #313D7A",
+"X1 c #3E4D8A",
+"X2 c #529030",
+"X3 c #2B3574",
+"X4 c #384584",
+"X5 c #55BF18",
+"X6 c #364382",
+"X7 c #344180",
+"X8 c #3B4469",
+"X9 c #8089B0",
+"X0 c #547153",
+"Xq c #6C9946",
+"Xw c #283374",
+"Xe c #374586",
+"Xr c #364385",
+"Xt c #263172",
+"Xy c #464D6D",
+"Xu c #4A5988",
+"Xi c #303D7F",
+"Xp c #2F3B7E",
+"Xa c #1E296A",
+"Xs c #4F5579",
+"Xd c #2D397C",
+"Xf c #1D2769",
+"Xg c #587946",
+"Xh c #2B377A",
+"Xj c #2A3579",
+"Xk c #3D4A85",
+"Xl c #32396D",
+"Xz c #283377",
+"Xx c #273376",
+"Xc c #273176",
+"Xv c #677197",
+"Xb c #263175",
+"Xn c #252F74",
+"Xm c #7D819C",
+"XM c #465491",
+"XN c #222D71",
+"XB c #222B71",
+"XV c #212B70",
+"XC c #1F296E",
+"XZ c #1E296D",
+"XA c #3E4C89",
+"XS c #373E6B",
+"XD c #43527A",
+"XF c #3B4886",
+"XG c #2B3673",
+/* pixels */
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.sXt.7Xz Y.7 E WX%XB t L.l.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.sXG _ 9 w.M K.SXO YX@X$ W !X*X- (.q.B.# a.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.sXF.o.o.k 9 w.M K.S.[ Y.8.8 W !X*X- (.qX>XCXCXX a.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s H x x.' ..k.) 9 w.M K.S.[ Y.8.8X% !X*X- (.qX>XCXZ.w.w uXo a.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.sX=.R.K x.'.o.k.) 9 w.M p.S.[ Y.8.8X% !X* / (.qXCXCXZ.w u u u.Z.1.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.D k bX=.K x.'.o.k.) 9 w.M p.S.[ Y.8.8X% !X* / (.qXCXCXZ.w u u i.Z.ZXo a.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.G.G k.RX= x x.'.o.k.) 9 w K p.SX+ Y EX$X% !.9XV.q.qXCXCXZ.w u u.Z.Z.Z P P 6.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.V.G.G k b.R.K x.'.'.o.k.) 9 w K pXOX+.7 EX$X&X*X-XV.qX>XC.B.w u u u.Z.Z P P P P.1.}.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s G.G.G.G k.RX=.K x.'.o.k.) 9 w.M K pXO.-X@.8.8X&X*X-XV.qXCXCXZ.w u u i.Z.Z P P PXfXo 6.}.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s R.G.G.G k b.R.K x.D.'.o.k.) 9 w.M p.SXO.-X@.8.8 !X* / (.qXCXCXZ.w u u i.Z.Z P P PXfXoXo 6.}.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s G.G.G.G k k.RX=.K x.' ..o.k.) 9 w K p UX+.; E.8.8 !.9XV.q.qXC.BXZ u u i.Z.Z P P PXf IXoXo.1 6.}.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.V.G.G.G k k.RX=.K x.D.'.o.k.) 9 w.MX. pXOX+ e E.8.8X*X-XV.qXCXC.B.w u u uXX.Z.Z P P PXfXfXo.1.1 6.}.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.G.G.G k k bX=.K x.D.fX,.AXFX4.W w K p.SXO YX@X$ W !X*X- (.qXCXC.BXZXZ u.C.C.CXXXXXXXXXX PXfXf.1.1 6.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.G.G.G k k.RX=.K.eX#X#X#X# C C M H.M p pXOX+.7 EX$X% !.9XV (.q.q t t t t t t t J J J.> y.B.,XXXXXXXf.l.#.s.s.s.s.s.s",
+".s.s.s.s.s.D.G k k b.RX=.K.e .2.3.3.3.3.3X0.Y.: l UXO YX@ J W.8.!.9.0.0.0.0.0.0.0.0.0.0 e e.0X X X J J.>.>.,XaXa 5 a.s.s.s.s.s",
+".s.s.s.s.s k k b.R.RX=.KXv .2.r 4 4 4 4.r.r zX8XlXO Y.7 E JX%.8.! !XNXNXN q q q q q q q q q.-.-.-.-.-.gX X J J.,., 5.s.s.s.s.s",
+".s.s.s.sX= b.R.RX=.K.eX# .2Xq 4 4 4 4 4.r.rXq zXyXl.6Xc E.>X%.8.8X%.n.n.n.n.n.n 0 0 0 0 0.&.&.n.[.[.[.*.-.-.g.gX J., 5.s.s.s.s",
+".s.s.s H.RX=X=.K.e xX# *.3 4 4 4 4 4.r 3 3 3.r @ mX8Xl.vXn JXn.8.8 0 0 0 0.v.v.v.v.v.v.v.v.v.v.`XtXtXt.&.&.&.*.-.-.g.g...P.s.s.s",
+".s.s.s x.K.K x x.DX# *.3Xq 4Xq.3.3X0 z d d d 7 @X2.EX8.c NX$XbXbXbXbXbX@X@X@XxXxXxXxXxXxXx.5._._._Xw.v.v.`XtXt.&.&.-.-.g.+.s.s.s",
+".s.s.s x x x.'.'.f *.3.r 4 4.3.x.x M ^ ^ :X8X2 ' ' @.EXS.c.vXcX@X@X@XzXz.5.4.4 D.4.4 D D D D D D D D.5._._Xw.a.aXt -.&.-.-.s.s.s",
+".s.sXF.'.'.' .X,.H.3Xq 4 4.r.3Xy ^ X _ hXlX8 m @ ' 'X2.EX8. Xw.8.8.4.4 D DXjXj.z.z.z.z.z.z.z.z.z.z.z.( D D._._._ %.a N N }.P.s.s",
+".s.s.o ..o.o.k SX0.r 4 3 4.rX0 ^ _ K p p vXl.].{ ' ' '.{.].c.U.8.8XjXjXhXhXh.<.<.<.j.j.j.j.j A A A.@.@.@.z #.( D._.U %.aXt }.s.s",
+".sXG.o.k.k.k.I SX0.r 3 3 7.3.Y gXp p p U D.6X8.]X2 ' [.$.E.cXl.8 FXh.<.<.jXdXd./././.h Z Z Z Z Z./././ A.i.@.@ # $ $.U %.a N.+.s",
+".s _.k.).).) ]XD.3 4 3 3 8.Y ^X. p.SXOX+.7Xx.cXS.].{.$ ' mX8Xl.8 F UXdXdX..hXpXp < < <XiXiXi.O.O.O.O.^ Z Z./ +.i.@ # $ $.U %.+.s",
+".s 9 9 9 9 9 H.x.3 3.r.r zX8 l.S UXOX+ Y.7X@.6.cX8.EX2 @X2.E.bXl lXd.hXpXp <XiXi.Q.Q.Q.Q V.Q.Q.Q.Q.X.X.X.O.O Z h +.i # v $.U.a.s",
+".s w w w w w ^.H 8 3.r 7.bXl.(XOXO.4 TX@.7 T.7.4XlX8.E.$.$.{.EX8Xl ZXpXiXi.Q.Q V B > > > > | > > | | V V.Q.X.O.O Z./ +.i # $.U.s",
+"Xt.M.M.M < g.Y.3 7 3 7 zX8 v DX+ Y.7X@X@X@ T.4.4X3Xl.b mX2X5X2.3.2X<.O.Q B B.=.d.d ; ; ; ; ; ; ; ;.yX7X7 | V V X.O o h +.i # v %",
+".7 K K K l.:X0 @ @ ' dXyXl.4.7.7X@ EXcX@X@ T.4XjXj.zXSX8 m [X5 7.3 ^X<.=.=.d ;.%XrXrXr = = = = =X6X6X6 ;.yX7 | | V.XX<.L h l #XG",
+"Xz.S.S.S #XS.E @ ' 'XgX8.6X@X@ E EX$ EX@Xz.4.4X+XOXhXlX8 mX5X5 @.3X8.:.= ;.%XrXrXr & & & &.T &X4X4X4X4 =X6X6.y | g.:X< o.L h l v",
+" YXO.[.[. .c m ' ' '.E.c N E J J.> J EX@.g.-.-.& U U }.c.] 1X5 'XqXy ^ {.%XrXe &.T.T n.p.p.p.p n n n.TX4X4 sX6.y ^ ^ ^ gX<.L h #",
+".7 Y Y Y.UXS.E @.$.$.].c }X$ WX%X%XnXbX@Xz.4XjXh.<Xd lX<X8.EX2 [X2.E.Y M s &.T.p.I.I.I c c c c c c.IXF.p nX4 H :.Y.bXy ^X<.X.L l",
+" EX@.8.8.!Xm.E.{ 7 7.3Xv. X%.8.8.8.8XbX@.8.8 F FXdX. F FXm.2 m [.$.{.3Xm F 2.I c.~.~.~ , j j.~.~.~.~ c cX9X9Xm.|.]X2.2Xm F FX< h",
+" WX$.8.8.!.!X8.E.3.3 .! e !.!.!.8.8XbX@.8.8 F FXdX. F F.!Xm.EX:X:.$.3XmXm 2 c j , , , , O ` , , , ,X1 jX9X9.2.3X2.u.3XmXmX9 g.L",
+"X% W WX% !.[ N.c.c.c. e /.9.9 !X% 0XbX@.4XjXh UX.XpXi.Q.: ^.] 1X: [Xg.YXD c j O O ` ` ` ` ` ` ` ` ` `X1XkXD.] 1 1 r m : ^X7 gX<",
+"XB ! ! ! !X*.-. . ..X (X-XV.0XN.n 0XbXz.4Xj.<Xd.hXiXi B g ^Xy.3XqX5X2.E.bXSXk O X g g g ) ) g g g g.JX1XlX8.E 1 1 1.]XS.6 vX7 X",
+" tX*X*X*X*X*.9X-X- /XVXV ( (.0XN.n 0X@Xz DXh.<XdXpXi.Q.=.= { ^Xm.3.{.{.{ m.xXD `.J f f f f f f f f f.J `XD.Y m r 1.u.] ^ H.yX7 g",
+" LX-X-X- / /XVXVXV (.q.q.q.q.0XN.n 0X@.5 DXh.jX.XpXi B.= ;.% HXm.2 mX2X5X2.E.Y.A ` f . . ~ ~ ~ ~X;X;.V S.Y.EX2X5X2.EXy M H s.y g",
+".l ( ( ( ( (.q.q.q.q.qXCXC.q.0 q.n.vX@.4XjXhXd.h <.Q B.d.%Xr &X9Xm.Y m [X: 1X0 C.V . ~ Q Q.t.t Q QXM.V C.].u 1X5Xg.Y :XF s s.y g",
+".s.q.q.q.q.q.qX>XCXCXCXCXC t.0 q.n.vXx.4Xj.<XdXpXi.Q.= ;XrXe.T.p M.xXgX5X:X: zXs C ~.t.t.t.F.F.F Q Q CXs m 1X: r m.x MXFXF s s.s",
+".s.BX>X>XCXCXCXCXCXC.B.B.B t.0 q.n.vXx D.z.<./XpXi V.d.%Xr &.p cXkXD z.{.{X5Xg.H C Q Q.F.F.F.F.F.F Q C.x m r r r mXDXkXkXF ] s.s",
+".s.#XCXCXCXCXC.BXZXZXZ.wXZ t.0 q 0.vXx.4.z.<./ <.Q B.dXrXr.T.I.~X9 SX8 zX2.$X2 z.HXu.f.F R R R R G G.Y mX2 [ r 1.]XDXkXAXkXF.:.s",
+".s aXCXZXZXZXZ.w.w.w u uXZ t.0 q 0.vXx.4.z.j./ <.Q > ;Xr &.T.I.~.~ jXS.x z.{.{.{ z.HXu R R R R R GXuX0.u r [ r.u.bXDXkXAXkXF.:.s",
+".s.sXX.w.w.w.w u u u u u u t.0 q 0.vXx D.z.j.h <.Q > ;Xr & n.I.~ , O.: C.Y zX2.$X2 z.HX# G x.e.eX#X# z 1X: rX2.].Y S SX1XkXF.s.s",
+".s.s a.w u u u u u u i u.C t.0 q 0.vXx D.z.j ZXi.Q > ; = &.p c , , ` g ) C.H dX5.$.{ z.HX#.e.e.eX#.HXgX5.{.{ z.xXD.V.AX1XA ^.s.s",
+".s.s.s u u u u u i i.ZXX.C t e q 0.vXx D.z.j ZXi V > ; = &.p c j O ` ) f CXs zX: rX5X2 z *X#X#X# * zX2X5X2 z.Y C.V.V.V.AXA.s.s.s",
+".s.s.sXo u i.Z.Z.Z.Z.Z.Z.C J e q.&.v.5 D.z.j ZXi.Q | ; =.T.p c j ` ` ) f.N CX0.u r [X5.{ d * * * d.{.{X5 d.HXu.mX;.N.V.AXk.s.s.s",
+".s.s.s a.Z.Z.Z.Z.Z.Z P.ZXX J.0.-.&.v._ D.z A Z.O.Q > ; = &.p c.~ , ` g f.N.f.Y.]X2 r r.$X2 d d dX2.{.{ 1 z.HXuXM ~.N.V.A M.s.s.s",
+".s.s.s.s.1.Z.Z P P P P PXX JX .-.n.`._ D.z A Z.O.Q > ; =X4 n c.~ , ` g f . ~ C.x.].u 1X5X5X5X5X5X5X5 1.uX0Xu.f.m ~.N.V S.s.s.s.s",
+".s.s.s.s.sXo P P P P P PXX.>X .-.[Xt._ D.z A./.O.Q | ;X6X4 n c.~ , ` g fX; ~.N C.YX0 zXgX2X: 1 1X2Xg zX0.HXu.f.mX;.N.A.s.s.s.s.s",
+".s.s.s.s.s a P P P PXf PXX yX .-.[XtXw D.z.@./.O.X |.yX6X4 n.I.~ , ` g fX;XM Q Q GXuX#.H z.u.u.u z *X#X# G G.mXMX;.N M.s.s.s.s.s",
+".s.s.s.s.s.s 6 PXfXf IXfXX.B J.-.[Xt.v.5.(.@./.^.X VX7X6X4.TXF cX1 `.J fX; ~ Q Q.m.mXuXu.H.b.b.b.HX#Xu G G Q.mXM.N.A.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.1XoXoXoXf P., J.g.*.&.v._ D.@ A Z.X VX7 ; =X4.p c jX1 `.J fX;XM Q.F R R R GXuXuXu G R R R R G.mX;.V.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.} 6XoXoXoXfXX.>X .-.&.`._ D.z.i Z.O.Q |.yX6X4 n 2.~X1X<.J ) f ~XM Q G R R G G G G G R R R Q.m ~.V M.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.} 6.1.1XfXX.>X .-.&XtXw._ #.@./.O.X VX7X6 s.T 2.~XAX< `.J fX; ~XM Q Q.F R R R R R R G G.mXM.N ^.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.} 6.1.1XX., J.g.*Xt.a._.(.@ + Z.O V |.y =X4X9 2 cX<X1 `.V.NX; ~XM.m Q Q G G G G Q.m.m ~.N ^.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.} 6.1XfXa J.g.-.&.a._ D #.i h.O X |X7X6 sX9 2 c.LXAX1 `.V.NX;X; ~XM.m.m.m.m.mXMXMX;.V ^.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.} 6.lXa.,X .-.&Xt %._ $.@ + Z.O V |X7X6 s.TXF cXAXAX1 `.V.V.NX;X; ~ ~ ~ ~X;X;.N.V M.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.# 5., J.g.- -.a.U $ #.i./ o.X gX7.y s s nXF cXAXAX1 ` `.V.V.N.N.N.N.N.N.N.A.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s a 5.,.g.-.& N %.U $ # + hX< X gX7X9X9 s lXF c cXAX1X1 ` ` `.V.V.V.V.A M.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s 5...g.- N.a % $ v.i +.L.O g gX9X9 s # nXFXFXkXkXAXAX1X1.A.A.A S.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.P.+.- }Xt.a.U $ #.i h.LX< g FX9.y v s s ]XFXFXkXkXkXAXAXk M.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.P } N %.U $ # l h.L.X FX9X7 v.y s s s ]XFXFXF ^.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.+.+.a.U v # l h.LX< g gX7X7.y.y s s.:.:.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s",
+".s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s %XG v # l h.LX< X g g g.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s"
+};
diff --git a/arts/builder/pics/Synth_WAVE_SQUARE.xpm b/arts/builder/pics/Synth_WAVE_SQUARE.xpm
new file mode 100644
index 00000000..4f5a1671
--- /dev/null
+++ b/arts/builder/pics/Synth_WAVE_SQUARE.xpm
@@ -0,0 +1,323 @@
+/* XPM */
+static char * WAVE_SQUARE_xpm[] = {
+"64 64 256 2",
+" c None",
+". c #161E54",
+"+ c #429224",
+"@ c #465A84",
+"# c #56CA0C",
+"$ c #2E3E64",
+"% c #66E614",
+"& c #3A4E74",
+"* c #3E821C",
+"= c #96E64C",
+"- c #222E64",
+"; c #7AD63C",
+"> c #4EAE1C",
+", c #5A6A9C",
+"' c #324674",
+") c #5EDA0C",
+"! c #565EA4",
+"~ c #464E8C",
+"{ c #263664",
+"] c #52BE0C",
+"^ c #6ACE2C",
+"/ c #6EF614",
+"( c #6A7694",
+"_ c #52629C",
+": c #92FE2C",
+"< c #4E5A8C",
+"[ c #7E86AC",
+"} c #2E3E7C",
+"| c #3E4684",
+"1 c #82FE24",
+"2 c #1A265C",
+"3 c #5EBE24",
+"4 c #4AA21C",
+"5 c #5AD20C",
+"6 c #AAFE44",
+"7 c #425684",
+"8 c #222E74",
+"9 c #465684",
+"0 c #2E3674",
+"a c #767AA4",
+"b c #3E4E8C",
+"c c #82DE44",
+"d c #7AFE1C",
+"e c #52BA0C",
+"f c #364684",
+"g c #56C60C",
+"h c #4E5A9C",
+"i c #363E84",
+"j c #1E266C",
+"k c #62CA24",
+"l c #6A7294",
+"m c #56BE1C",
+"n c #6AD62C",
+"o c #72FE14",
+"p c #469A14",
+"q c #4A5A94",
+"r c #56669C",
+"s c #9EFE3C",
+"t c #42527C",
+"u c #22325C",
+"v c #5E6AB4",
+"w c #6A76BC",
+"x c #222A64",
+"y c #465694",
+"z c #2E367C",
+"A c #52B61C",
+"B c #4A5E84",
+"C c #5ECA1C",
+"D c #2E3E6C",
+"E c #6AEE14",
+"F c #A2E65C",
+"G c #96D26C",
+"H c #3A467C",
+"I c #62E20C",
+"J c #46528C",
+"K c #2A3674",
+"L c #3E4A84",
+"M c #1E2A5C",
+"N c #4EAA1C",
+"O c #B6FE4C",
+"P c #2A3274",
+"Q c #7A82AC",
+"R c #8EE24C",
+"S c #4E5E9C",
+"T c #36427C",
+"U c #56C21C",
+"V c #569E34",
+"W c #5AB624",
+"X c #3E527C",
+"Y c #82DA41",
+"Z c #72D234",
+"` c #6EFA14",
+" . c #9AFE38",
+".. c #4E5E94",
+"+. c #828EB4",
+"@. c #324283",
+"#. c #42528F",
+"$. c #3A4A88",
+"%. c #469E1C",
+"&. c #4E569A",
+"*. c #36428C",
+"=. c #162254",
+"-. c #4A5A8B",
+";. c #9EE65C",
+">. c #4EB21C",
+",. c #5662AA",
+"'. c #2A3A6C",
+"). c #6AD22C",
+"!. c #727E9C",
+"~. c #8AFE2C",
+"{. c #1E2663",
+"]. c #5EC61C",
+"^. c #4AA61C",
+"/. c #66D224",
+"(. c #263274",
+"_. c #767E9C",
+":. c #1E2A6C",
+"<. c #62CE24",
+"[. c #72D634",
+"}. c #76FE1A",
+"|. c #5E66AC",
+"1. c #26326C",
+"2. c #626EB3",
+"3. c #2E3A7D",
+"4. c #52BA1C",
+"5. c #324274",
+"6. c #46529C",
+"7. c #3E4A94",
+"8. c #5ACE0C",
+"9. c #666EB4",
+"0. c #727AA4",
+"a. c #626EA4",
+"b. c #6676AC",
+"c. c #32425C",
+"d. c #5E6EA4",
+"e. c #7E8AAC",
+"f. c #6E7AC0",
+"g. c #A6EA64",
+"h. c #66EA14",
+"i. c #7ADA3C",
+"j. c #62DE0C",
+"k. c #52C20C",
+"l. c #5ED60C",
+"m. c #6AF214",
+"n. c #B2FE4C",
+"o. c #A6FE44",
+"p. c #96E254",
+"q. c #3E8624",
+"r. c #2E3A72",
+"s. c #5ECE24",
+"t. c #3A4A7A",
+"u. c #6672BC",
+"v. c #8ADE44",
+"w. c #5EC224",
+"x. c #5ABA24",
+"y. c #3E4E84",
+"z. c #9AE65C",
+"A. c #5AC61C",
+"B. c #4A9A24",
+"C. c #5A66AC",
+"D. c #1A2264",
+"E. c #767EAC",
+"F. c #3E4E7C",
+"G. c #9AE654",
+"H. c #262E6C",
+"I. c #364677",
+"J. c #2A366C",
+"K. c #72F614",
+"L. c #96FE34",
+"M. c #525A94",
+"N. c #323E7E",
+"O. c #AEFE4C",
+"P. c #424E8E",
+"Q. c #7EFE20",
+"R. c #3A4685",
+"S. c #525AA4",
+"T. c #5ABE22",
+"U. c #263264",
+"V. c #4A5696",
+"W. c #323E74",
+"X. c #66E214",
+"Y. c #BAFE54",
+"Z. c #525EA3",
+"`. c #3A427C",
+" + c #5AC21D",
+".+ c #1A225C",
+"++ c #5A62AC",
+"@+ c #6ED22E",
+"#+ c #62C624",
+"$+ c #222A6E",
+"%+ c #66CE25",
+"&+ c #323A84",
+"*+ c #828AB4",
+"=+ c #469224",
+"-+ c #5ACA0C",
+";+ c #52AE1C",
+">+ c #62DA0C",
+",+ c #86FE24",
+"'+ c #4EA21C",
+")+ c #5ED20C",
+"!+ c #262E74",
+"~+ c #86DE44",
+"{+ c #6ED62C",
+"]+ c #5A669C",
+"^+ c #A2FE3C",
+"/+ c #626AB4",
+"(+ c #56B61C",
+"_+ c #52AA1C",
+":+ c #7E82AC",
+"<+ c #92E24C",
+"[+ c #72FA14",
+"}+ c #525E94",
+"|+ c #868EB4",
+"1+ c #4A9E1C",
+"2+ c #3A428C",
+"3+ c #52B21C",
+"4+ c #8EFE2C",
+"5+ c #4EA61C",
+"6+ c #76D634",
+"7+ c #56BA1C",
+"8+ c #4A529C",
+"9+ c #424A94",
+"0+ c #6AEA14",
+"a+ c #7EDA3C",
+"b+ c #56C20C",
+"c+ c #6EF214",
+"d+ c #7A7EAC",
+"e+ c #465A8C",
+"f+ c #3E8224",
+"g+ c #222E6C",
+"h+ c #464E94",
+"i+ c #26366C",
+"j+ c #6EF61C",
+"k+ c #92FE34",
+"l+ c #4E5A94",
+"m+ c #3E468C",
+"n+ c #1A2664",
+"o+ c #46568C",
+"p+ c #4E5AA4",
+"q+ c #72FE1C",
+"r+ c #469A1C",
+"s+ c #4A5A9C",
+"t+ c #425284",
+"u+ c #223264",
+"v+ c #4A5E8C",
+"w+ c #5ECA24",
+"x+ c #2E3E74",
+"y+ c #62E214",
+"z+ c #465294",
+"A+ c #2A367C",
+"B+ c #3E4A8C",
+"C+ c #1E2A64",
+"D+ c #B6FE54",
+"E+ c #2A327C",
+"F+ c #364284",
+"G+ c #3E5284",
+" (.P P E+E+(.!+8 $+$+:.{. ",
+" x r.F+F+&+3.3.A+(.!+(.!+8 8 $+8 D.. . . ",
+" 0 L 9+m+2+F+N.3.z !+A+0.E.!+$+8 :.:.:.j D.D.. . ",
+" r.h &.V.h+9+R.*.i &+3.3.!+(.E.0.8 8 $+8 8 $+:.:.n+D.. . . . ",
+" M.! ! &.8+P.7.m+*.@.&+z 3.!+E+a E.!+8 $+:.:.:.:.$+:.:.j j D.. . ",
+" &./+|.++S.&.6.h+7.m+*.i i 3.A+8 (.E.0.8 8 8 $+$+$+j :.:.j :.j :.D.. . . ",
+" a.2.v ,.Z.p+V.h+9+m+m+@.i &+3.A+A+(.(.!+!+$+8 :.:.$+j :.:.j :.j :.j n+D.. . ",
+" ~ w u./+C.++Z.p+V.6.7.7.*.i &+} z z E+E+!+(.8 8 $+8 $+:.:.j j :.j :.j j j j D.. . . ",
+" `.w u.u./+C.,.S.V.6.h+7.m+m+*.&+&+A+A+8 (.0.0.!+8 $+8 $+:.:.:.j :.j j n+j j n+j D.. . . ",
+" &.a u.u./+C.,.Z.p+V.6.h+7.f *.i } &+3.A+$+E+a 0.8 $+$+:.:.$+:.:.:.j :.:.:.j :.:.j :.D.. . . ",
+" `.u.w 9.2.v C.! S.&.6.h+7.m+*.*.i &+A+A+A+$+(.a 0.8 8 $+8 :.:.:.j :.j j j :.n+j :.n+j n+D.. . . ",
+" ~ f.w u.9.v C.! Z.p+V.6.b 7.m+*.i } &+3.z E+8 !+0.0.8 :.$+:.:.j j :.j :.:.j j j n+j j :.j j D.. . . ",
+" 9.u.9.2.|.C.,.Z.p+V.6.h+7.7.f *.i &+3.A+A+E+(.!+!+8 8 8 $+$+$+:.:.:.j j :.:.:.:.j :.j n+j n+n+D.. . ",
+" b.b.a.u., , ++_ Z.s+o+9+B+R.F+i N.} 3.A+i+1.(.i+g+g+8 $+:.:.:.:.$+:.:.:.:.:.:.:.:.:.:.:.:.:.j j :.D.. . ",
+" | G g.F F p.G.p.R v.v.c Y a+; 6+[.@+).^ ^ %+k w+w+A.%+%+B.8 8 8 8 $+8 8 8 8 :.$+$+8 $+8 8 $+8 :.:.:.:.n+D.. ",
+" a.F Y.O O n.6 o.o.o.s .L.: 4+4+~.,+,+Q.Q.d d }.}.}.[+j+ +g+$+8 $+8 8 8 8 8 8 8 8 8 8 $+$+8 $+8 $+$+$+:.. . ",
+" &., G.O O.G.<+<+v.v.Y Y a+a+i.6+Z [.).)./.%+<.k w+A.s.j+j+U u+!+(.8 !+8 !+!+(.(.(.!+(.(.(.g+(.g+8 8 g+$+g+:.n+. ",
+" W.++}+p.O.= B l+-.V.#.t+P.L $.T ' 5.x+r.r.0 '.i+i+1.- u /.` +1.8 8 (.(.(.(.(.!+(.(.(.(.(.!+(.!+(.1.H.8 H.- - x . . ",
+" ~ S.M.R o.R J 6.z+h+9+B+$.`.2+i N.&+&+z A+E+E+(.(.(.(.U. +/ U i+E+E+(.E+(.(.A+(.(.i+(.(.i+(.i+(.(.(.(.(.- f+^.q.M 2 ",
+" h h -.R o.v.#.h+P.b 7.R.2+*.@.i &+3.3.A+A+(.(.E+E+(.P i+ +/ T.U.(.(.E+i+A+A+(.A+A+E+A+K E+A+E+P E+i+P (.U.^.8.4 u+.+ ",
+" 0 8+6.P.~+s Y L 7.m+m+m+2+*.i N.N.&+A+z E+A+(.(.(.E+(.$+i+k / m i+A+A+A+A+A+3.0 z '.A+A+'.A+'.A+K A+K K i+{ ^.8.4 U.g+2 ",
+" h+P.h+L c .Y $.m+m+R.*.*.N.i &+3.3.z A+K E+E+E+(.i+A+8 J.<.m. +'.K A+0 A+z A+3.3.z 3.3.z 3.z 3.3.0 A+K z U.^.8.4 U.- . ",
+" 2 9+7.9+| a+L.; H f *.i i i &+3.z A+A+A+(.(.(.(.E+E+(.A+g+J.k m.m '.3.3.3.3.r.3.3.} 3.3.} 3.} 3.r.3.3.3.K '.J.^.8.4 U.J.1.{. ",
+" &+B+m+R.t.i.: i.i *.i i i } 3.&+3.z A+(.E+E+A+E+A+A+A+A+!+i+k c+m r.A+3.3.3.3.3.3.3.N.N.&+N.&+} 3.} 3.3.3.&+{ ^.8.4 J.P H.. ",
+" &+F+*.*.T i.~.[.T N.i &+&+3.A+A+A+E+E+(.A+E+K E+A+K A+A+z '.m E m D 3.} } } N.N.N.N.N.@.N.N.N.N.N.N.N.N.3.W.'.^.8.4 { J.P U. ",
+" F+F+F+N.W.Z ~.[.x+&+3.3.A+A+A+E+E+E+(.E+(.(.E+K E+A+K 3.3.r.m m.m '.} N.N.N.N.N.@.N.N.N.N.@.i @.N.N.N.N.N.r.'.4 8.4 '.K J.P ",
+"!+N.&+N.3.r.{+,+).'.3.A+z A+A+A+A+(.E+(.(.E+i+A+A+A+A+A+3.u+r.#+E m r.N.N.i @.*.i F+F+F+F+F+@.T F+T @.@.@.T i $ 4 8.4 '.r.'.'.K ",
+"P &+3.&+&+'.@+1 @+E+A+A+A+A+E+(.!+(.(.(.(.A+E+E+K z 3.3.3.!+x+].E 7+5.i N.@.F+@.f F+f f f F+R.F+F+F+T T T N.@.D ^.# 4 r.3.3.z K ",
+"(.3.A+A+A+'.).Q./.1.A+A+E+(.(.(.(.(.(.E+(.A+i+A+A+A+3.3.N.(.x+].E 4.x+F+F+F+F+F+f F+F+R.f f R.f f R.f F+f F+@.D ^.# 4 $ r.3.r.0 ",
+"E+E+!+!+!+x %+Q.k - $+:.E+(.$+$+$+$+(.(.8 8 !+!+K 3.!+!+(.P x+#+E 7+5.F+*.F+R.f R.R.$.R.R.R.R.R.R.f R.R.`.I.`.5.4 -+4 x+N.W.3.3.",
+"E+E+E+(.A+1.%+Q.k 1.(.!+(.!+8 8 8 !+(.P (.P K 3.A+3.3.3.} N.x+7+E 7+5.f f f R.f $.R.R.B+$.$.$.$.B+R.$.$.R.f R.5.^.# 4 D N.N.r.3.",
+"(.(.E.E.0.l <.d {+l a 0.8 8 0.a 0.0.(.(.E.E.E.E.3.3.Q :+Q [ x+7+h.7+!.[ *+*+R.B+*++.+.*+B+B+|+|+*+|+$.R.*+*+e._.4 -+5+!.[ [ N.r.",
+"8 8 a a a l w+}.n l 0.a !+!+0.a a 0.!+E+_.E.d+d+3.3.[ [ Q [ 5.4.h.m Q e.*+*+7.$.*+*++.|+b B+*+|+*+|+b B++.*+*+_.4 -+_+!.[ [ @.N.",
+"!+(.8 8 8 C+w+}.w+g+8 8 8 8 $+$+8 !+(.(.A+A+i+3.3.} 3.N.@.@.5.(+% A 5.m+R.$.$.b b P.P.b b b #.b P.b b b B+L t.I.4 # 1+5.T @.i 3.",
+"$+8 !+8 !+u+C }.C x $+:.:.$+8 $+(.(.(.(.A+A+A+3.3.} 3.N.i @.5.w.% 7+'.} N.&+B+9+N.N.N.N.#.P.N.@.i i P.P.N.N.N.'.4 # %.J.0 J.T N.",
+":.$+8 $+$+x A.[+A.:.:.$+$+8 :.8 8 8 (.E+K 3.3.A+3.N.N.N.@.F+' T.% A D $.$.b b G+#.#.#.z+z+#.z+#.#.#.#.#.P.P.y.t.4 g 1+' I.R.T N.",
+":.:.8 8 :.g+A.[+A.C+8 :.:.$+8 8 !+!+(.(.E+K 3.3.3.N.@.@.F+F+I. +% A r.b b b P.b P.z+#.#.y y J z+#.#.#.#.#.P.y.t.4 g 1+I.f f I.T ",
+"j $+$+:.$+C+A.` U :.:.:.:.:.$+$+(.(.(.A+K A+3.3.N.N.i i *.`.5.3 I A D b b P.P.6.#.#.z+y z+y y y y y z+o+#.#.#.t.4 g %.I.R.R.`.N.",
+" :.$+:.:.n+U j+U {.$+j :.:.8 $+8 (.(.A+A+A+3.3.} N.@.F+f f T (+X.3+H b #.#.#.y y y y y y y y V.y y y o+o+J J t.4 g 1+I.R.f R. ",
+" :.:.$+:.C+ +/ m :.:.$+$+$+$+8 !+(.E+i+K 3.3.3.N.N.i @.*.R.I.A I A $.P.b #.#.#.z+y V.q V.s+q q q q y y z+z+#.F.4 g %.t.L R.I. ",
+" . j :.j n+m c+U C+:.j :.:.8 8 !+(.E+A+A+3.3.&+} @.F+F+F+f I.x.j.A D #.P.6.y y y y y q q s+q s+q q s+e+y y J F.1+g 1+t.L R.N. ",
+" D.:.j :.- m m.m n+j :.:.$+$+8 !+(.(.A+K A+3.} N.N.F+f R.R.I.T.y+3+x+P.#.#.6.y V.s+s+s+s+l+h l+h h q s+e+y o+F.1+b+%.H $.H - ",
+" n+:.j 2 m E m n+j j :.:.8 8 8 (.(.A+r.3.3.N.N.N.@.F+f R.I.x.j.3+x+#.z+y y s+y q v+S S S S S ..h l+h q V.y X 1+b+%.t.t.| ",
+" D.j :.n+e E e n+:.:.:.$+$+g+(.(.P K A+3.3.3.N.@.F+f R.$.I.x.j.3+W.#.#.y y y s+S h s+S S _ _ S S S q h e+V.F.%.k.p t.y.U. ",
+" D.:.{.4.0+7+n+n+j :.:.8 g+!+(.(.A+A+3.} N.N.N.@.*.F+R.t.>.) >.F.z+z+y y q q s+S S S S S _ _ S S q h q q t 1+b+p t.P. ",
+" n+j M + 4.+ n+j n+:.$+$+!+(.(.K P K 3.&+} N.F+F+f f $.I.3+>+;+L #.y z+q V.s+..S S _ _ r _ _ _ _ S v+q V.t 1+k.1+t.`. ",
+" . n+j M M 2 j :.j :.$+:.g+(.(.i+A+K 3.3.&+N.N.F+R.`.R.I.W ) A $ & t+y.7 t+7 9 @ e+e+-.v+v+v+e+-.o+9 7 t t.1+] p t.H ",
+" n+n+j n+j n+j n+j :.8 8 8 (.P A+A+K 3.} N.F+F+*.f f I.(+l.5 > _+> ;+N N N N N N N N N ^.^.5+5+'+4 1+1+4 ] ] p c. ",
+" D.:.:.:.j :.:.:.$+$+H.8 (.(.K 3.r.3.3.N.N.@.F+R.f t.W l.l.l.5 5 5 )+8.8.8.-+-+# # -+A.g g g g b+k.k.] ] ] 1+c. ",
+" D.j j j n+j n+{.:.g+$+!+(.P K K 3.3.N.} @.F+f f $.T V (+> N _+N N N _+N N N ^.5+5+5+^.4 4 4 1+4 1+p %.1+p * ",
+" . j :.j j :.j j g+g+8 (.(.E+K r.3.&+N.@.i F+F+R.f H t.t.& y.y.y.t+#.t+7 e+e+o+o+-.-.-.@ @ 9 9 9 F.F.F.t. ",
+" n+j n+n+n+j :.:.8 H.8 (.i+K A+0 } r.N.@.F+R.f $.$.$.b b #.J o+o+y s+V.q h S ..S ....h q q q o+V.o+t ",
+" . D.j j n+j j :.g+H.!+P (.K 3.K N.N.N.@.@.f `.R.*+*+B+} b P.#.y J V.V.q q S q S s+..S q V.V.o+J P.| ",
+" . n+n+j C+:.$+:.8 H.(.P K K 3.3.3.W.i T F+f f *+*+b N.P.#.P.#.y y y y q V.q q q q V.q e+y o+J J. ",
+" . =.n+j j $+g+8 8 (.(.P K K r.3.} N.i F+`.R.*+*+L } b #.#.#.#.y y y e+q V.q y e+y y o+z+#.H ",
+" . D.n+{.:.:.g+H.(.(.i+K z 3.x+&+N.@.@.f f *+*+R.r.B+L P.P.#.#.J z+z+y y y V.V.y z+z+t J. ",
+" . =.j C+$+:.g+!+(.P K K z r.3.W.N.N.T F+T R.B+$.b L b P.P.#.#.J #.o+J 7 #.J o+o+#.| ",
+" D.j :.g+$+g+!+(.i+K A+r.3.3.N.N.N.T R.f f | R.b L y.P.P.#.#.J #.#.z+J #.t+P. ",
+" . j g+g+g+!+!+P K K r.3.r.N.N.@.@.[ *+f r.R.$.L y.y.L y.b P.#.P.#.#.P.H ",
+" {.$+!+u+P (.K K A+r.3.N.N.N.N.[ [ f r.R.$.$.$.$.b b P.y.P.b y.L ",
+" 2 $+g+1.!+(.K K r.K r.} N.i [ [ F+'.`.R.R.L L L $.L L y.L | ",
+" C+1.P (.K K 3.3.r.W.} Q :+F+0 f `.R.f R.R.| $.T ",
+" x x P K K z r.N.W.N.N.@.i @.T `.f H W.W. ",
+" J.K K K 3.r.x+r.N.T T @. "};
diff --git a/arts/builder/pics/Synth_WAVE_TRI.xpm b/arts/builder/pics/Synth_WAVE_TRI.xpm
new file mode 100644
index 00000000..1ff5cf52
--- /dev/null
+++ b/arts/builder/pics/Synth_WAVE_TRI.xpm
@@ -0,0 +1,305 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 234 2",
+/* colors */
+" c #394684",
+" . c #3AA021",
+" X c #33407E",
+" o c #313E7C",
+" O c #43B123",
+" + c #505AA1",
+" @ c #1D2865",
+" # c #2C3877",
+" $ c #283473",
+" % c #273272",
+" & c #38912C",
+" * c #253070",
+" = c #37457B",
+" - c #232E6E",
+" ; c #263F53",
+" : c #314175",
+" > c #2D3A7B",
+" , c #2C387A",
+" < c #3E4D85",
+" 1 c #3C468D",
+" 2 c #283276",
+" 3 c #374288",
+" 4 c #49BC25",
+" 5 c #232E71",
+" 6 c #343E85",
+" 7 c #465590",
+" 8 c #757CA7",
+" 9 c #202A6E",
+" 0 c #2F3A80",
+" q c #1E286C",
+" w c #1D286B",
+" e c #50619D",
+" r c #2D387E",
+" t c #3F4D89",
+" y c #3A4784",
+" u c #253076",
+" i c #384582",
+" p c #5661A6",
+" a c #323F7C",
+" s c #303D7A",
+" d c #4E599E",
+" f c #3A4787",
+" g c #293573",
+" h c #242F6E",
+" j c #285640",
+" k c #323F7F",
+" l c #44508A",
+" z c #2F3B7C",
+" x c #2E3B7B",
+" c c #2C3979",
+" v c #1B2565",
+" b c #293576",
+" n c #394589",
+" m c #263173",
+" M c #252F72",
+" N c #242F71",
+" B c #5864A4",
+" V c #34427A",
+" C c #212B6E",
+" Z c #2F3B7F",
+" A c #1E296B",
+" S c #344C66",
+" D c #43963C",
+" F c #1D276A",
+" G c #1C2769",
+" H c #2C377C",
+" J c #2B357B",
+" K c #4C5C98",
+" L c #4A5A96",
+" P c #242F74",
+" I c #475693",
+" U c #222D72",
+" Y c #202B70",
+" T c #43528F",
+" R c #33407C",
+" E c #323E7B",
+" W c #41508D",
+" Q c #364482",
+" ! c #354281",
+" ~ c #2E3A7A",
+" ^ c #7F88AF",
+" / c #2C3B6E",
+" ( c #7B84AB",
+" ) c #263272",
+" _ c #364285",
+" ` c #475299",
+" ' c #28356A",
+" ] c #294357",
+" [ c #242E70",
+" { c #212C6D",
+" } c #1F2A6B",
+" | c #1D2869",
+". c #1C2668",
+".. c #495994",
+".X c #354087",
+".o c #242E73",
+".O c #232E72",
+".+ c #465591",
+".@ c #222C71",
+".# c #212C70",
+".$ c #202A6F",
+".% c #1F2A6E",
+".& c #42518D",
+".* c #1E286D",
+".= c #3D4B88",
+".- c #3B4986",
+".; c #294F49",
+".: c #33417E",
+".> c #626DB6",
+"., c #3FB01F",
+".< c #2D3978",
+".1 c #2C3777",
+".2 c #3D4C81",
+".3 c #2A3575",
+".4 c #1A2362",
+".5 c #283373",
+".6 c None",
+".7 c #263171",
+".8 c #222D6D",
+".9 c #365466",
+".0 c #323D80",
+".q c #202B6B",
+".w c #70799F",
+".e c #313E75",
+".r c #2D397B",
+".t c #1D2768",
+".y c #2B3779",
+".u c #3DAA20",
+".i c #293377",
+".p c #495893",
+".a c #182059",
+".s c #222D70",
+".d c #333D84",
+".f c #45548F",
+".g c #35427C",
+".h c #313B82",
+".j c #42508C",
+".k c #347B35",
+".l c #2E397F",
+".z c #1D276B",
+".x c #404E8A",
+".c c #4E5E9B",
+".v c #4C5C99",
+".b c #3C4A86",
+".n c #2C3873",
+".m c #4A5A97",
+".M c #7986A4",
+".N c #399729",
+".B c #3B7F3F",
+".V c #455492",
+".C c #6772BA",
+".Z c #313E7B",
+".A c #303C7A",
+".S c #202A67",
+".D c #21315E",
+".F c #2E3A78",
+".G c #41A42A",
+".H c #1F2D5C",
+".J c #1C2663",
+".K c #5D68B0",
+".L c #2B3675",
+".P c #334080",
+".I c #33486C",
+".U c #327C2F",
+".Y c #1E2B5E",
+".T c #2B396E",
+".R c #384488",
+".E c #253072",
+".W c #242E71",
+".Q c #212C6E",
+".! c #303C80",
+".~ c #202A6D",
+".^ c #42BA1D",
+"./ c #24365D",
+".( c #1E286B",
+".) c #414F8A",
+"._ c #1C2669",
+".` c #2B367B",
+".' c #4D5D99",
+".] c #1F354E",
+".[ c #293479",
+".{ c #4B5B97",
+".} c #273277",
+".| c #657096",
+"X c #2C5C40",
+"X. c #485794",
+"XX c #27336D",
+"Xo c #647C81",
+"XO c #242F6A",
+"X+ c #335B54",
+"X@ c #3F4D8B",
+"X# c #2F3B78",
+"X$ c #307433",
+"X% c #48C31F",
+"X& c #344180",
+"X* c #303D7C",
+"X= c #525DA4",
+"X- c #303B7C",
+"X; c #2B3777",
+"X: c #4A559C",
+"X> c #48CC18",
+"X, c #343F83",
+"X< c #222D6E",
+"X1 c #313D80",
+"X2 c #424D94",
+"X3 c #303D7F",
+"X4 c #404B92",
+"X5 c #1E296A",
+"X6 c #2D397C",
+"X7 c #3E4990",
+"X8 c #1D2769",
+"X9 c #327931",
+"X0 c #2A3579",
+"Xq c #283377",
+"Xw c #273376",
+"Xe c #263175",
+"Xr c #4DAE34",
+"Xt c #2B6634",
+"Xy c #475692",
+"Xu c #294950",
+"Xi c #378A2F",
+"Xp c #212B70",
+"Xa c #44528F",
+"Xs c #43528E",
+"Xd c #346B4A",
+"Xf c #1F296E",
+"Xg c #1E296D",
+"Xh c #2E3980",
+"Xj c #233A54",
+"Xk c #1D276C",
+"Xl c #2C377E",
+"Xz c #3E4C89",
+"Xx c #7E8CAA",
+"Xc c #495897",
+/* pixels */
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.E 2.i.[Xq u P.o.@ 9 A.t.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.n E 3.X.d 0 r J.[.} u P.o U.@ Y.$Xf.4.4.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6 fX2X4 1.R.X.d 0 r.W.[ 8 8 P.o U.@ Y.$.$XfXf.(.4.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6 ! + d `X2X4 1.R.X.h 0 r.W.[ 8 8.o.o U.@ Y.$.$XfXg.*.* q._.4.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6 p pX= d `X2X7 1 3 6.h 0Xl.W.[ 8 8.o.o UXp Y.$.%XfXg.* q q q.z. .6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6 K.K.K p +X: `X2X7 1 3 6.hXh H.W.[ 8 8.o.o UXp Y.$XfXfXg.* q q w.z.z._.4.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.C.>.K.K p +X: `X2X7 1 3 6.h.l H JXq.} P.o.o.@Xp.$.$XfXfXg.* q q.z.z.z F F. .6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6 l.C.C.>.K pX= dX: `X4X7 n 3.d.h.l.`.[Xq u P.o U.@Xp.$.$XfXf.* q q q.z.z F F F F. .a.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.p.C.C.>.K.K p + d `X2X7 1.R.X.d 0 r J.s.} 8 8.o U.@Xp.$.%XfXg.* q q w.z.z F F FX8._. .a.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6 K.C.C.C.>.K pX= +X: `X2X7 1 3 6.h 0 H J.s u 8.w.sXp.$.$.$.%XfXg.* q q w.z.z F F FX8._._. .a.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.p.C.C.C.>.K.K p + d `X2X4 1 n.X.d.h.l HX0 C u.w.w.8 C 9.%XfXfXfXg q q w.z.z F F FX8 G._._. v.a.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6 l.C.C.C.>.K.K pX= dX: `X2X7 1 3.X.d 0 r.`.[.q [.|Xo.Y @X5XfXgXfXf.* q q q.(.z.z F F FX8X8._. . v.a.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.C.C.C.>.K.K pX= +X: `X2X4 1 n 3 6.h.l H.[.} *XOXj.;.].H @ qXgXfXfXgXg q q q q.(.(.(.(.( FX8X8. . v.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.C.C.>.>.K.K pX= + d ` `X4X7 1 3.X.d 0 r J 2.7.DXj.;XtXu.H @ qXf 9 9 9 9 9 9 9.~.~.~.~ } q A.(.(.(X8.t v.6.6.6.6.6.6",
+".6.6.6.6.6 K.>.>.K.K.K pX= + dX: `X2X7 1 n.X.d.h.l.`.[ %XO.] j DXr j.].Y.~ 9.#.#.#.#.Q.Q.s.s.Q.Q.Q.Q {.~.~.~ AX5X5 |.4.6.6.6.6.6",
+".6.6.6.6.6.K.K.K.K p pX= + dX: `X2X7 1 n 3 6.h 0 H.[ %.DXj j.UXr OX .].Y {.s 5 5 5 5 5 5 5 5 5 5.s.s.sX<.Q { {.q.q } |.6.6.6.6.6",
+".6.6.6.6 p.K.K p pX= + dX: ` `X2X4 1 n 3.X.d.h r J.5XXXj j.U., 4 4Xt.].D - 5.o.o M M.E.E.E.E.E M N N N [ 5 - -X< {.q.q |.6.6.6.6",
+".6.6.6 ! p p pX= + + dX: ` `X2X7 1 1 3.X.d.h rX0.5 'Xj j.U .X%X%X%XtXj.D [.E m m m m m m m m m m m m m.E * M [ [ -X<.8 {.J.6.6.6",
+".6.6.6 +X= + + d dX: ` `X2X4X7 1 n 3.X.d.h.l H $XXXjX .U OX%X>X>.^XtXj.D m mXwXqXqXqXqXqXqXqXwXwXw.5 m m % m m * * h -.8.q.6.6.6",
+".6.6.6 d dX:X:X: ` `X2X2X4X7 1 n 3.X.d.h.l.`.3 'Xj j.U.N.^X>X>X>.^XtXj.D.5Xw.i bX0X0X0X0X0 b b bXw $.5.5 % % ) % m.7 * h -.6.6.6",
+".6.6 f ` ` ` ` `X2X2X4X7 1 1 n 3.X.d.h.l H.3XX ;X .k O.^X%X>X>X>X%XtXj ' $ bX0.y.y.y.y.y.y.y.yX;X; g $ $ $ $.5.5.5 %.7.7 *.Y.6.6",
+".6.6X2X2X2X2X2X4X7X7 1 1 n 3.X 6.d.h.l ,.3 ' ]X .k.N O.NXi ..^ 4 4XtXj ' b.y , , ,.r.r.r.r.r ,X; g '././ 'XX.3 b b $.5 %.7 h.6.6",
+".6.nX4X4X7X7X7X7 1 1 n 3 3.X.d.h.h r H.3XX ]XdXi O O O.UX X9.N O 4XtXj 'X; ,X6 > > > z z z > >.n.T ].; ]./ ' g.L.L.L g $.5 %.S.6",
+".6 E 1 1 1 1 1 n.R 3.X.X 6.d.h 0 r.y g ' ]Xd &.G O &X9 j ;X XiXr 4Xt ; ' , > z ZX3X3X3X3 z x.n / ]X X$.;./ '.n # #.1.L.3 $.5.S.6",
+".6 3.R.R 3 3 3 3.X 6.d.d.h 0.l H J $XX ].B DX% 4 OX9.; ;./.;.U.N.,Xt ] ' > zX3X1X1X1.0X1X1X# / ]XdXi.NX ] '.<.F.F.< #X;.L.3 %.6",
+".6.X.X.X 6 6 6.d.d.h.h 0.l r.`.[.5 ' ]Xd D.G 4.NX9.;Xj./ 'Xu.U.N.^X$ ] /.AX3.0 k.P.P k o s / ]X &.N .X ].TX#.A z x.F.< #.L.3.6",
+".E.d.d.h.h.h.h.h 0 0.l r H J.[ %XX ;Xd &X% 4 OX9.;Xj 'XXXX ;X9XrX%.BX+.I o kX,X, !X,X& E.e ]XdXi.,.u .X ] / s.Z o.A.A.F.< #.L $",
+" 2 0 0 0 0Xh.l.l r H H.`.[ 2 %.DXjX Xi.G 4.NX9 jXj ' g g g ;.UXrX%.BX+.I k.P ! _ !X& a / ]X Xi.N., &X$Xu /.e a a k o.Z.AX#.F # g",
+".i r r rXl H H.` J JX0.[.}.7XOXj j.U O O.^.k.;Xj ' g ,X;.n ;X9XrX% DX+.IX& ! _ _ Q.: : ]X .U.u.u.,.k.; ].e E X XX& X a o.AX#.F.L",
+".[ J.W.W.W.W J.[.s.s C.q *.D.] j.U.N 4.G &X Xj.D $X; * hXOXu.UXrX% DX+.I ! Q _ !.: : ]X X9.N.,.G DXd S.I V.g ! ! !X& X a.Z.AX# #",
+"Xq.[.[.[.[.[XqXq.} u u [XOXj j.U.,.^X% DXdXu ' g.y , z.<.nXu.U.N.^ DX+.I Q Q ! V ]X X9.u.,.^ D.B.9 = = i i i Q !X& X a o.A.F",
+" u.} 8 8 8 8.} u 8.w.w.|Xj j DXr 4Xr.G.BXoXo.w 8 HX6 ( 8.wXoXi ..^.BXo.w ( ( Q.IXo.B D.G.u.GXrXoXo.w i i ^ ^ ^ ^ i Q ^ ^ ( (.ZX#",
+" P u 8 8 8 8 P.o 8.w.|Xo j.U 4 4 4Xr.BX+.w.w 8 8 H z ( 8.wXoXi ..^.kXo.w ( 8 V S.B D O O., DXoXo.MXx.=.= ^ ^ ^ ^ i ^ ^ ^ ( a.A",
+".o P P.o.o.o.o U.s.Y.] j.U &.u.N.UXdX+ ] g gX0.` z ZX3.A.eX+ &.G.^X$ S.I =.I SX .k &.u &.kXd.9.9 < <XzXzXz.=.=.- f i Q !X& X.Z",
+".@.o.o.o.o.o.o C.q.] jX$.u.u.uX9 jXu 'XXXqX0 ,X6 z.!X1 s.eX+ &Xr 4Xt ;./ ' ;X .k . . .X9X+.9.I : E a WX@.Z.Z s.A.b.-.F #.n.n.: a",
+" 9 U U U U U.@.~.S.]Xt.U.uXiX$ jXj./XX %.iX0 ,X6 ZX3.0 o :X+ &Xr 4X$ ; ] SX .k &.u &.kX+ S.2 <.).&.& T W WX@X@Xz.=.b y i QX& a",
+" A.@.@.@XpXpXp A @.]X$Xi .X$.;.].SXO mXwX0.y.r z ZX1.P o :X+ &Xr 4.k.;X X .k.u.u.u.kX+ S.2 tXaXa.V.VXa T.& W WX@Xz.=.- y i ! R",
+".t Y Y Y Y Y.$.( @.]XtXtXt.;.].H.q hXeXqX0 ,X6 zX3X1.P a :X+XiXrX% &Xt.kXi.N.u &.kX+ S =.)Xs.V.V I.+.V.V T T.& WX@Xz.=.- y i Q.:",
+".6.$.$.$.$.$.$X5 @.] j j.;.].Y.q 5.EXw.iX0 ,X6 zX3.0X, X VX+Xi .X%.u.N ..,.u.u.kX+ S.2.j.V IX.X.X. I I.+.VXaXs.&.xX@Xz.b.- i.6",
+".6Xf.$.$.%XfXf.( |.H.].].].Y.S {.O.EXq b.y , > ZX1 kX, X VXu.U .X>.^.,.,.u &.kX+ S.2 l.fX.XcXc LXc..X. I.+.VXaXs.j.xXz.=.b y i.6",
+".6.4XfXfXfXfXf.( F.J.Y.Y.J.t 9.s M mXqX0.y , >X3X1.P !.: VXu.U.GX>X>X>.^.u.kX+ S.2.j I...m.m.m.m.m.m LX. I.+.VXa.& WX@Xz.b.-.e.6",
+".6.4XfXgXgXgXgXk.z v.J.J @.(.$.s M mXqX0.y.r >X3X1.P !.: VXuX9.GX>.^.^.N.kX+ S.2.j.+...m.v.v.v.v.v K.m LX. I.+.fXs.j.xXz.b.- V.6",
+".6.6.(.*.*.*.*.z.z FX8X8 FXf.Q 5.E mXqX0.y.r zX3.0.P !.: VXuX9.GX>.^.u.kX+ S.2 l I...v.v.'.c.c.c.c.'.v.m LX.Xy.VXa.&.) t.= y.6.6",
+".6.6.4.* q q q q.z.z G.z wXf.Q 5.E mXqX0.y.r zX3.0.P !.: VXuX9.G.^.NX$X+ S =.j.f...m.v.c.c.c.c.c.c.c.' K.m..X..+XaXs.) tXz V.6.6",
+".6.6.6 q q q q q w w.z.( q 9.s 5.E mXqX0.y.r zX3 k.P !.: VXuX9 & ..kX+ S.2.).VX..m.v.'.c.c e e e e e.c.'.{ LX.Xy.fXs.j.xXz.6.6.6",
+".6.6.6._ q w.z.z.z.z.z.z q.~.s 5.E mXq b.y.r zX3 kX& !.: V ]XtX$X$X+ S = tXs IXc.m.v.c.c e e e e e e.c.c K L.pXy.fXs.j.x.b.6.6.6",
+".6.6.6.4.z.z.z.z.z.z F.z.(.~.Q 5.E mXw b.y.r zX- k.P !.g V ]X .BXo S / < T.VX.Xc.m.v.c.c e e e e e e e.c K L.pXy.fXa.j.x =.6.6.6",
+".6.6.6.6. .z.z F F F F F.(.~.Q 5 M mXw b.y.r zX- k.P !X&.g.IXuXoXo =.e.xXa.VX. L.m.v.c.c e e e B e e e.c K L.pXy.fXs.j <.6.6.6.6",
+".6.6.6.6.6._ F F F F F F.(.~.Q.s N mXw b.y.r xX- k.P ! ! ! : :.w.M.b E.&.V IX.Xc.m.v.c.c e e e e e e.c.' K L.pXy.fXs.x.6.6.6.6.6",
+".6.6.6.6.6.4 F F F FX8 F.( }.Q.s N m.5 b.y c >X- k.P ! ! Q.g V.M (.= a.&.V.+ I...m K.'.c e e e e e e.c.'.{ LX..+.fXs.2.6.6.6.6.6",
+".6.6.6.6.6.6. FX8X8 GX8.( q {.s N m m bX; , ~ z k kX& ! Q i i f.bXz W TXa.V IX. L.m.v.'.c.c e e.c.c.' K L.pXy 7Xa.).6.6.6.6.6.6",
+".6.6.6.6.6.6.6. ._._._X8 F A.~X< [.E m bX; #.r z o kX& ! Q i f.=XzX@ W T.V.+ IX. L.m K.'.c.c.c.'.' K L..Xy.+.f.j.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.a. ._._._X8.(.~.Q 5 * % $ b.y.< zX* k.P ! Q f ^ ^Xz.Z W.& T.V.+ IX. L.m.{ K K K K.{ L..X.Xy.f.& =.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.a. . . X8.(.~ { - M m.5 bX; , ~X- o kX& Q i ^ ^.=.ZX@ W TXa.V.+ IX... L L L L L L.pXyXy 7.& =.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.a v. . .( A { - [ m.5 bX; #.F z o kX& ! Q ^ ^.= sX@ W.&XsXa.V.+XyX.X..p.p.p.pX.Xy.+.f.& =.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.a v. X8X5.qX< [ * % $ b.1.<.AX- a XX& Q i ^ ^.-.AXzX@ W.&XsXa.f.V.+XyXyXyXyXy.+ 7.f.& =.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.a v.tX5.q { - * m.5 b.L #.F z o kX& ! Q i f.b.=XzX@.x.j.&XsXaXa.f.f.f.f.f.fXa.j =.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6 v | }.qX< h.7 % $.L.1.< x.A o XX& ! Q i .-.b.=XzX@.x W.j.&XsXsXsXaXsXsXs.).6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.4 |.q.8 - *.7.5 g.L #.F.A.Z a XX& ^ ^ i.F y.-.=XzXzX@.x.).).j.j.j.j.x.2.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6 | {.8 h.7 % $.3X;.<.F.A o a X ^ ^ Q # y.-.b.=XzXz t t.x.x.x <.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.J.q - *.7.5 $.L #.<X#.A.Z a ( ^ !.n i y.-.b.b.b.=XzXz.b =.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.Y h %.5.3.L #.FX#.A o ( (X&.n Q i i y.-.- y V.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.S.S %.3.L #.FX#.A.Z a X.:X& ! Q i i.e V.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6",
+".6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6 $ g.L #.FX#.A.Z a a R.:.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6"
+};
diff --git a/arts/builder/pics/Synth_XFADE.xpm b/arts/builder/pics/Synth_XFADE.xpm
new file mode 100644
index 00000000..296b9584
--- /dev/null
+++ b/arts/builder/pics/Synth_XFADE.xpm
@@ -0,0 +1,313 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"64 64 242 2",
+/* colors */
+" c #374482",
+" . c #3BA318",
+" X c #39477A",
+" o c #354280",
+" O c #395766",
+" + c #313E7C",
+" @ c #303C7B",
+" # c #2F3C7A",
+" $ c #33921A",
+" % c #338C1A",
+" & c #2C3877",
+" * c #1A2462",
+" = c #4D5D94",
+" - c #253070",
+" ; c #36A316",
+" : c #2E711F",
+" > c #46558D",
+" , c #838CB5",
+" < c #202A6B",
+" 1 c #1C2667",
+" 2 c #32801C",
+" 3 c #39B212",
+" 4 c #283276",
+" 5 c #384289",
+" 6 c #364287",
+" 7 c #242E72",
+" 8 c #283A62",
+" 9 c #232E71",
+" 0 c #343E85",
+" q c #333E84",
+" w c #747AA6",
+" e c #202A6E",
+" r c #424F8C",
+" t c #212D65",
+" y c #1E286C",
+" u c #2E387F",
+" i c #3FC111",
+" p c #1C266A",
+" a c #2B367C",
+" s c #314A5A",
+" d c #2A3771",
+" f c #1A235E",
+" g c #495996",
+" h c #32741F",
+" j c #475594",
+" k c #232E74",
+" l c #445391",
+" z c #333F7D",
+" x c #243261",
+" c c #27523C",
+" v c #313D7B",
+" b c #3B4988",
+" n c #374584",
+" m c #848DB5",
+" M c #376948",
+" N c #2E3B7B",
+" B c #2D397A",
+" V c #33871C",
+" C c #1B2565",
+" Z c #648088",
+" A c #2E5249",
+" S c #222D6F",
+" D c #323D82",
+" F c #55C733",
+" G c #1F296C",
+" H c #1D276A",
+" J c #404E89",
+" K c #1C2769",
+" L c #283378",
+" P c #263176",
+" I c #394682",
+" U c #3AA915",
+" Y c #242F74",
+" T c #475693",
+" R c #232D73",
+" E c #455491",
+" W c #25306B",
+" Q c #202B70",
+" ! c #43528F",
+" ~ c #33407C",
+" ^ c #5F7286",
+" / c #1E296E",
+" ( c #404E8C",
+" ) c #2E3A77",
+" _ c #2D3876",
+" ` c #3BBA0F",
+" ' c #1B2661",
+" ] c #3A4886",
+" [ c #374483",
+" { c #354281",
+" } c #232E6C",
+" | c #2E3A7A",
+". c #3B488A",
+".. c #7C84AC",
+".X c #283474",
+".o c #384487",
+".O c #475299",
+".+ c #38457D",
+".@ c #232E6F",
+".# c #323F77",
+".$ c #1E286A",
+".% c #1C2668",
+".& c #2B367A",
+".* c #3C468E",
+".= c #4B5996",
+".- c #273276",
+".; c #4B5796",
+".: c #629174",
+".> c #354087",
+"., c #767EA9",
+".< c #757CA8",
+".1 c #222C71",
+".2 c #212C70",
+".3 c #44538F",
+".4 c #737AA6",
+".5 c #202A6F",
+".6 c #1F2A6E",
+".7 c #2F3A81",
+".8 c #1E286D",
+".9 c #414F8C",
+".0 c #1D286C",
+".q c #606BB1",
+".w c #4D5B9B",
+".e c #3B4986",
+".r c #1F3150",
+".t c #364381",
+".y c #34417F",
+".u c #435191",
+".i c #555FA6",
+".p c #69E23B",
+".a c #3E4D8C",
+".s c #2A3575",
+".d c #394787",
+".f c #293574",
+".g c #384586",
+".h c None",
+".j c #263171",
+".k c #222D6D",
+".l c #434D94",
+".z c #3E498F",
+".x c #1D2768",
+".c c #346146",
+".v c #1B2566",
+".b c #487453",
+".n c #2A3578",
+".m c #3C4D79",
+".M c #263174",
+".N c #2D5049",
+".B c #59D62E",
+".V c #2F6C23",
+".C c #45548F",
+".Z c #202B6E",
+".A c #313B82",
+".S c #285A30",
+".D c #1E296C",
+".F c #2E397F",
+".G c #1D276B",
+".H c #3E4C88",
+".J c #2A357B",
+".K c #1F2D59",
+".L c #1C2860",
+".P c #213947",
+".I c #283379",
+".U c #3B4885",
+".Y c #3BAD17",
+".T c #28346F",
+".R c #6B76BE",
+".E c #435090",
+".W c #2C6623",
+".Q c #313C7B",
+".! c #1E2A65",
+".~ c #4D589D",
+".^ c #357B25",
+"./ c #2B3675",
+".( c #3A4687",
+".) c #384685",
+"._ c #485498",
+".` c #273271",
+".' c #48598E",
+".] c #273567",
+".[ c #334080",
+".{ c #313E7E",
+".} c #838CB4",
+".| c #39B811",
+"X c #273274",
+"X. c #364086",
+"XX c #171F57",
+"Xo c #222C6F",
+"XO c #1D286A",
+"X+ c #6E769F",
+"X@ c #23493E",
+"X# c #293479",
+"X$ c #283278",
+"X% c #253075",
+"X& c #2E7524",
+"X* c #5965A8",
+"X= c #465592",
+"X- c #222C72",
+"X; c #212C71",
+"X: c #42518E",
+"X> c #323F7B",
+"X, c #202B66",
+"X< c #2F3B78",
+"X1 c #3D4B89",
+"X2 c #394785",
+"X3 c #364382",
+"X4 c #344180",
+"X5 c #323F7E",
+"X6 c #303D7C",
+"X7 c #24503B",
+"X8 c #404B8F",
+"X9 c #8089B0",
+"X0 c #2D3979",
+"Xq c #40B517",
+"Xw c #2B3777",
+"Xe c #3C478B",
+"Xr c #2D3F65",
+"Xt c #2E7A20",
+"Xy c #3C526D",
+"Xu c #47568F",
+"Xi c #212B6D",
+"Xp c #369A17",
+"Xa c #43528B",
+"Xs c #2C377B",
+"Xd c #3E4C86",
+"Xf c #3A458C",
+"Xg c #2F7824",
+"Xh c #273176",
+"Xj c #485893",
+"Xk c #252F74",
+"Xl c #222D71",
+"Xz c #212B70",
+"Xx c #6570B6",
+"Xc c #1F296E",
+"Xv c #42508D",
+"Xb c #1E296D",
+"Xn c #2E3980",
+"Xm c #2C377E",
+"XM c #3E4C89",
+"XN c #213652",
+"XB c #1C2661",
+"XV c #2A3672",
+/* pixels */
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.j 4 L.IX$ P Y k.1 e.D.x.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.hXV.Q 5.> q.7Xm a.IX$X% Y RX-X; Q.5Xc * f.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.e.lX8.* 5.> q.7Xm 7.I.< w Y RX-X; Q.5.5Xc / y f.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h o.~.~.O.lX8.* 5.> D.7Xm 7.I.< w k RX-X; Q.5.5XcXb.8.8 y.% f.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.iX*.i.~.O.lX8.* 5 0.AXnXm 7.I.< w k RX-X; Q.5.6XcXb.8 y y.0.G.%.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.w.qX*.i.i.~.O.l.zXf 5 0.AXnXm 7.I.< w k RX-X; Q.5XcXcXb.8 y y.G.G.G.% f.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.hXxXx.qX*.i.~.~.O.l.zXf 5 0.A.FXm.JX$ PXk k R.1Xz.5.5XcXcXb.8 y y.G.G.G H H.v.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.hXa.RXx.q.qX*.i.~.O.O.l.zXf 6 q.7 u aX#X$ PXk RXlX;Xz.5.5XcXc.8 y y.0.G.G H H H H.%XX.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.;.R.RXx.qX*.i.i.~.O.lX8.* 5.> D.7Xm aXlX$.<.4 RXlX;Xz.5.6XcXb.8 y y.G.G.G H H H H.% 1XX.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h =.R.RXx.q.qX*.i.~.~.O.l.zXf 5 0.AXnXm.J.@Xh w.4 RX-X; Q.5.6XcXb.8 y y.G.G.G H H H H.%.% 1XX.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.;.R.RXxXx.qX*.i.i.~.O.lX8.*Xf 6 q.7.F a.JXo P w.4 R.1Xz.5.5XcXcXb y y.G.G.G H H H H K.%.%.%.vXX.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.hXa.R.RXxXx.qX*.i.i.~.~.O.l.z.* 5X. D.7Xm aX#Xo P w.4XlX;Xz.5.6XcXc.8 y y y y.G.G H H H H H.%.%.%.vXX.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.hXxXx.q.qX*.i.i.w.=._.l.lX8.*Xf 6 0.A.FXm.J.IXhX% Y RX-X; Q.5.6XcXcXbXb y.D.GXO C C C CXB C * 1.v.%.v.h.h.h.h.h.h.h",
+".h.h.h.h.h.hXxXx.q.qX*X*.i = =Xj.C.EX8.zXf 5X. D.7Xm aX#X$ PXk 7 R.1Xz Q.5.5 e e e e eXc G.!.L.L.L.L.L.L 'XB.x.%.x C.h.h.h.h.h.h",
+".h.h.h.h.h.;.qX+ Z.:.:.:.:.:.:.b.bXy.U.o 5X. q.A.FXm.J.I.-Xi Y.4.4.1.2.2.2.2.2.2.2.2.ZX,.!.rX@X@X7X7X7X@X@.r.!.x.$.$ f.h.h.h.h.h",
+".h.h.h.h.hX*X* Z.p.p.p.p.p.p.p F F.b X.tX. q D.7Xm aX#X$ PXi k.4.4 RXlXlXlXlXl 9 9Xl SX,.KX7Xp U.|.|.| ; $X@.!.! < <.x.h.h.h.h.h",
+".h.h.h.h.iX*.i ^.p.p.p.p.p.p.p.p.B.b MXyX> @.7 u a.J.IXh PXi k.4.4 7 Y Y Y Y Y Y 7 } tXNX7Xg.|.| `.|.| ; $X@ tX,XiXi <.x.h.h.h.h",
+".h.h.h oX*.i.w ^ F.p.p.p.p.p.p.p.p.B F MXr ) u a.JX#X$ PX%XiXk w wXkXkXkXk.M.MXk.j t xX7Xp.| i i ` `.| ; $X@ t <.@ S.kXiXB.h.h.h",
+".h.h.h.~.i.~.~.' ^.b.b.b.b.b.b F.B.B.B.^.cXrXV.X.I L.-Xh P P P P P P P.-.-.-X - WXNX7Xg.|.|.| V.S.S c cX@XN W } -.@.@.k <.h.h.h",
+".h.h.h.~.~.~._ j.3 r JXd.e X X.b F.B.B FXq.c.].TX$ P.-.-.-.-.-.-.-.- L L L 4.X W x c $ 3 i.|Xp c x x.].].] W.j.j.j.j -.@.@.h.h.h",
+".h.h.e.O.O.O.O.lX8X8Xe.(.o.t.y s M.^ F F F.^ AXN W - P.- L.@ L.,.,X#.n.n L.` WXN cXg 3 3 3Xg cXN.].T.T.T.T.T.X.X.X.`.j.j -.!.h.h",
+".h.h.l.l.l.l.l.lX8.z.*.*Xf 5 0 vXr.cXq F.BXq . c x W.-.- L.@X#.,.,.&.&.&.n.T x c $ 3 i 3Xp c 8.T & &X0 &XwXwXw.s.f.X.X.`.j -.h.h",
+".hXVX8X8X8.z.z.z.*XfXf 5 6X. D @ _Xr.c.^ iXqXq.^ cXN W.` L.@.n.,.,.&.&.f.TXN cXg.Y 3 3Xg cXN d _ B N | BX0X0 & &././.f.X.`.` t.h",
+".h.Q.*.*.*XfXfXf 5 5 6X. 0 D.A.FXmXV.] A .Xq iXqXp c x WX#.@.&.,.,XsXs.T.] c $ U i.Y $ c 8 d N NX6X6X6 N N | |X0 & &./.s.X.X t.h",
+".h 5 5 5 5 5 5 6.> 0 q D.A.7.FXm.J.X.TXN A.^XqXqXqXg cXN.T.f.&XsXsXw dXN cX& U U UXg c 8 _X<.{X5X5.{.{ +X6X6 N # |X0 &Xw./.f.`.h",
+".h.>.>.> 0 0 0 q D.A.7.7.FXmXm a.J L.- W x cXpXq i.Y $ c.].TXs B B d.] c % U i U $ cXr )X5.[.[.[.[.[.[X5X5 + +X6 N N |X0 &./.f.h",
+".j q q D.A.A.A.7.7Xn.FXmXm a.JX#.IX$ P - WXN cXg.Y.Y.YX& cXN dX+X+ 8 cX& ; ; UX& AXr.#X> {X3 { { { {X4X4.[.[X5X5 + @ # |X0 &./.T",
+" 4.7.7.7XnXn.F uXmXm a a.JX#.IX$Xh PXh PX W x c $.Y i U %X7 8 ^ ^ c V ; ` ; % AXr.# {X3 [ [ [ [X3X3X3 { {X4.[.[X5 + v #X< ) &XV",
+" LXmXmXmXmXmXm a a.J.JX#.IX$.- P PX% P.-.-.j WXN cX& U . .X& c.b.bX& ; ; ;X& AXr.#.y n.g.g.).g.).).) n [X3X3 {X4.yX5X5 + #X< )./",
+".I a 7 7 7 7.JX#Xl.@XoXoXh PXiXiXiXi P.-.@ S.k t x c V ; ` U ; . . U ` ; V AXr.# n.g.d.(.(.(.(.dX2X2.).) n [ [X3 o.yX5X5 + #X< _",
+"X$.I.I.I.I.IX$X$X$Xh P PX%Xk Y k kXk P.- LX#X#.X.TXN cXg.Y.Y 3 U U U UX& AXr.#.t.d b. b b b b b b b ].(X2.) n [X3 {X4X5X5 + # )",
+" PX$.<.<.<.< P P.< w w w Y 7.4.4.4 w P.-.,.,.,.,Xs.T ^.b .Xq ` ` ` U ..b ^.4.d b.}.}.} ,X1X1.}.}.}.}X1 b.}X9X9X9 [ X9...... vX<",
+" YX% w w w wXkXk.4.4.4.4 R R.4.4.4 w P.-.,.,.,.,Xs.T ^.b ..Y ` ` ` U ..b ^ w b. , , m m.a.a m m m mXMX1.}.}X9X9.) [X9X9....X> #",
+" k Y Y k k k k R R R RXlX-.1.1 R 7Xk P.-X#.&.&Xs B d 8 cXp ; ` ` ` UXp cXr ~X1X1.a.a.a ( ( ( ( ( ( (.a.aXMX1 b.e ]X2 [ .t.y ~ v",
+".1 R R R R R RXlXlX-.1X;X;Xz.2Xl YXk P L.n.&.&./ d 8X@.VXp ; ; U U ;Xp.VX@XN.+.e +X5 z zX:X: z z z z.9 ( + + v #.e.e ) _ _./.y +",
+" eX-X-X-X-X-.1X;X;X;XzXz Q Q.2Xl YXk.- L.n.&.&.T.]X@Xg % UXp $ . .Xp U $.^.N.# I (Xv.u.u.u.u ! !.u !X:Xv.9 (.aXMX1.e ]X2 I.t o ~",
+".DX;X;X;X;X;XzXzXz Q.5.5.5.5.2Xl YXk.- L L.X.TXNX@.S % % %.V c.b.b.V % % %.W.NXr IXM.u l E E E E l l l !X:Xv (.aXMX1.e ] I I.t ~",
+".x Q Q Q Q Q.5.5.5.5.5.6.6.5.2Xl Y.M.- 4.n.T xX@X& V ; %Xg.NXr ^ ^.NXt % ; %Xg A XXd l EX= j jX=X=X= E l ! !Xv.9.aXMX1.eX2 I.t ~",
+".h.5.5.5.5.5.5.5.6.6XcXcXc e.2Xl Y.MX .j WXNX@.S V V V.S.N 8.# ~ ~Xr.N.W % V V.S AXyXdXa TXjXjXj T T TX= E lX:Xv (XM.H.e.U I I.h",
+".hXc.5.5.6XcXcXcXcXcXcXcXc e.2 9 YXkX W xX@.V 2Xp VX&.NXr.#.) ] b.+.#.NXg VXp VX& A.m J T g g g g gXj TX= E lX:Xv (XMXd.eX2 I.h",
+".h *XcXcXcXcXcXcXbXbXb.8Xb e.2 9 7 } WXNX@.S 2 2 2.SX@ 8.# o.d.}.}.U dXr A.S V V 2.S AXyXa.C.=.=.=.= g g TX= E !Xv.9XM.H.e.U.#.h",
+".h f /XbXbXbXb.8.8.8 y yXb e.2Xl 7 t x.P.V 2 $ 2 :X@Xr.# [.g b.} ,.a + I X AX& 2Xp 2X& A.mXa.=.=.w.=.=.=Xj TX=.C !Xv (XMX1.e.#.h",
+".h.h y.8.8.8.8 y y y y y y e.Z < t.r.P.S 2 2 2.SX@ 8X< ~ n.d. .} m.a +.HXdXy A.S 2 2 2.S AXy >Xj.w.w.w.=.=Xj T E !Xv.9XMXd.U.h.h",
+".h.h f.8 y y y y y y.G y.DXcXiX,.K.P.W h %Xt.VX@.] _X4X3.g.( b , m ( zX: !Xd.m AX& 2 % 2.V A.m >.w.w.w.w.= gXjX=.3X:.9XM.H.#.h.h",
+".h.h.h y y y y.0 H.% C C C.!.!.r.P.S : h h.SX@XN d # { [.g.( bX1.a (X:.u lXa JXy A.S 2 2Xt.S AXy >.'Xj.'XuXu T T.C !Xv J.H.h.h.h",
+".h.h.h.%.0.G.G p.% C ' '.L.L.K.P.W : V :.W.P.] d +.[X3 [.).( bX1.a (X:.u EX= T J.m A.VXt % h.V A.mXa >XaXa >XjX=.C !Xv J.e.h.h.h",
+".h.h.h f.G.G.G.% CXX.P.P.P.PX@.S : : :.S.PXN.T _.{.[ { [.g.( b.} m ( z ! E j T.CXaXy A.S h h h.S A A s s sXy >.C.C !Xv J.+.h.h.h",
+".h.h.h.h.%.G.G C '.P.S.W.W : : h 2 :.W.P x.T | NX5.[ { [.).d b.} m ( z ! EX=Xj g.=Xa.m A.V h 2 h : :.V.V.W O >Xa.C !XvXd.h.h.h.h",
+".h.h.h.h.h.% H C '.P.W.W h h h : :.S.P.r WXV BX6X5.[ {X3.)X2 b.} m ( z.u lX= T g.=Xu >Xy A.S h h h h h.V.V O.'Xa.CX: J.h.h.h.h.h",
+".h.h.h.h.h f H C '.P.W h 2 2 2.V.W.P.K W./ & NX6.{.[ {X3.)X2 b.} m ( z ! lX= T g.=.=.w >.m s.W.V.^ h h.^.^.b >Xa.CX: I.h.h.h.h.h",
+".h.h.h.h.h.h.v 1XBXN c.c M.c.cX7.P.r t -.sX0 |X6.{.[X4X3 n.) ]X1XM.a.9X: l E TXj g.=.=Xj >Xy O O.b.b.b.b.bXy >Xa.3 J.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.v 1.! x 8 8 8 8 x t }.j.X.n & B N +X5X4 { [.).( bX1.a (Xv ! lX= T g.=.=.= =Xj.'.'.'.'.'.'.' >.C.3Xa.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.hXX.v.v.!.!.!.! tX, < }.j.X.sXwX0 NX6X5.[ {X3 nX2.}.}XM +.9X: ! EX= TXj.=.=.=Xj.'.'.'.'.' > > >.3Xa X.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.hXX 1.%.% H.$ <Xi.@ -.j.X.fXwX0 |X6 +.[X4X3 [.)X9.}X1 + (Xv ! l EX= TXj g.=.=.=.=.=.=XjXjX=.CXa X.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.hXX.v.%.%.$ GXi.@ -.jX .XXw & | N +X5.[ { [ nX9X9 b v.a (XvX: l EX= TXjXjXjXjXjXjXj TX=.CXa X.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.hXX.v.% H.$Xi S.@ -.`.X.s &X0 #X6X5.[X4X3 [X9X9.e #XM.a.9XvX: !.C EX= T T T TX=X=.C.CXa X.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.hXX.v.x.$ <Xi.@ -.j.X.f./ & | N +X5.y oX3 [.) ].eX1XM.a (XvXv ! !.3.C.C.C.C.C.C.3Xa X.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h C.$ <Xi S.@.j.`.X./ &X0 N @ +X5.y { [X2.e.eX1XMXM (.9XvXvX: ! ! ! !X:X: J.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h f.x <.k.@ -.j.X.f./ & | # vX5X5X4X9X9 [ ) ].eX1.HXMXM (.9.9XvXvXvXv J I.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.xXi.k.@.j.`.X.sXwX0 | # +X5X5..X9 _X2 ].e.eXd.HXMXMXM J J JXd.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.hXB <.@ -.j.`.X./ &X0X< # +X5.....t _ I IX2.U.e.eX1Xd.H.H.e.+.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.! -.`.X.f./ & )X< # +.....y./.t I I IX2.U.e.U.#.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h t t.`.f./ & )X< # vX> ~.y o.t.t I I.#.#.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h",
+".h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.TXV./ _ )X< # v + ~ ~ ~.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h"
+};
diff --git a/arts/builder/pics/cr16-action-artsbuilderexecute.png b/arts/builder/pics/cr16-action-artsbuilderexecute.png
new file mode 100644
index 00000000..abd8f18a
--- /dev/null
+++ b/arts/builder/pics/cr16-action-artsbuilderexecute.png
Binary files differ
diff --git a/arts/builder/pics/cr22-action-artsbuilderexecute.png b/arts/builder/pics/cr22-action-artsbuilderexecute.png
new file mode 100644
index 00000000..d4fbdae4
--- /dev/null
+++ b/arts/builder/pics/cr22-action-artsbuilderexecute.png
Binary files differ
diff --git a/arts/builder/pics/hi16-app-artsbuilder.png b/arts/builder/pics/hi16-app-artsbuilder.png
new file mode 100644
index 00000000..cc030d39
--- /dev/null
+++ b/arts/builder/pics/hi16-app-artsbuilder.png
Binary files differ
diff --git a/arts/builder/pics/hi16-app-artscontrol.png b/arts/builder/pics/hi16-app-artscontrol.png
new file mode 100644
index 00000000..1271ba0a
--- /dev/null
+++ b/arts/builder/pics/hi16-app-artscontrol.png
Binary files differ
diff --git a/arts/builder/pics/hisc-app-artsbuilder.svgz b/arts/builder/pics/hisc-app-artsbuilder.svgz
new file mode 100644
index 00000000..72c9647d
--- /dev/null
+++ b/arts/builder/pics/hisc-app-artsbuilder.svgz
Binary files differ
diff --git a/arts/builder/pics/hisc-app-artscontrol.svgz b/arts/builder/pics/hisc-app-artscontrol.svgz
new file mode 100644
index 00000000..98633799
--- /dev/null
+++ b/arts/builder/pics/hisc-app-artscontrol.svgz
Binary files differ
diff --git a/arts/builder/portposdlg.cpp b/arts/builder/portposdlg.cpp
new file mode 100644
index 00000000..240b3a13
--- /dev/null
+++ b/arts/builder/portposdlg.cpp
@@ -0,0 +1,258 @@
+ /*
+
+ Copyright (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 "portposdlg.h"
+#include "structureport.h"
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlistbox.h>
+#include <kbuttonbox.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kseparator.h>
+#include <qlineedit.h>
+#include <stdio.h>
+#include <arts/debug.h>
+#include <qpushbutton.h>
+#include <kstdguiitem.h>
+
+using namespace std;
+
+PortPosDlg::PortPosDlg(QWidget *parent, Structure *structure) :QDialog(parent,"Props", TRUE)
+{
+ this->structure = structure;
+
+ setCaption(i18n("aRts: Structureport View"));
+
+ QVBoxLayout *mainlayout = new QVBoxLayout(this);
+ //QHBoxLayout *contentslayout = new QHBoxLayout;
+
+// object type
+/*
+ mainlayout->addSpacing(5);
+ QLabel *objectlabel = new QLabel(this);
+ QFont labelfont(objectlabel->font());
+ labelfont.setPointSize(labelfont.pointSize()*3/2);
+ objectlabel->setFont(labelfont);
+ objectlabel->setText(QString(" ")+i18n("Object type: ")+QString(port->owner->name())+QString(" "));
+ objectlabel->setAlignment(AlignCenter);
+ min_size(objectlabel);
+ mainlayout->addWidget(objectlabel);
+*/
+
+// port description
+
+/*
+ mainlayout->addSpacing(5);
+ QLabel *portlabel = new QLabel(this);
+ labelfont.setPointSize(labelfont.pointSize()*4/5);
+ portlabel->setFont(labelfont);
+ portlabel->setText(i18n("Port description: ")+ port->description);
+ min_size(portlabel);
+ portlabel->setAlignment(AlignCenter);
+ mainlayout->addWidget(portlabel);
+
+ int labelwidth = imax(portlabel->sizeHint().width(),objectlabel->sizeHint().width());
+
+ portlabel->setMinimumWidth(labelwidth);
+ objectlabel->setMinimumWidth(labelwidth);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler);
+ mainlayout->addSpacing(5);
+ mainlayout->addLayout(contentslayout);
+*/
+// list
+
+ listbox = new QListBox(this);
+
+ update();
+
+ listbox->setMinimumSize(100,200);
+ mainlayout->addWidget(listbox);
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler2 = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler2);
+
+// buttons
+
+ QHBoxLayout *buttonlayout = new QHBoxLayout;
+ mainlayout->addSpacing(5);
+ mainlayout->addLayout(buttonlayout);
+ mainlayout->addSpacing(5);
+
+ buttonlayout->addSpacing(5);
+ KButtonBox *bbox = new KButtonBox(this);
+
+ bbox->addButton(KStdGuiItem::help(), this, SLOT( help() ));
+ bbox->addStretch(1);
+
+ KIconLoader iconloader;
+ QButton *raise = bbox->addButton(i18n("&Raise"));
+ raise->setPixmap(iconloader.loadIcon("up", KIcon::Small));
+ connect( raise, SIGNAL( clicked() ), SLOT( raise() ));
+
+ QButton *lower = bbox->addButton(i18n("&Lower"));
+ lower->setPixmap(iconloader.loadIcon("down", KIcon::Small));
+ connect( lower, SIGNAL( clicked() ), SLOT( lower() ));
+
+ QButton *rename = bbox->addButton(i18n("R&ename..."));
+ connect( rename, SIGNAL( clicked() ), SLOT( rename() ));
+
+ QButton *okbutton = bbox->addButton(KStdGuiItem::ok());
+ connect( okbutton, SIGNAL( clicked() ), SLOT(accept() ) );
+
+/*
+ QButton *cancelbutton = bbox->addButton(i18n("Cancel"));
+ connect( cancelbutton, SIGNAL( clicked() ), SLOT(reject() ) );
+*/
+ bbox->layout();
+ //min_size(bbox);
+
+ buttonlayout->addWidget(bbox);
+ buttonlayout->addSpacing(5);
+
+ //mainlayout->activate();
+ mainlayout->freeze();
+}
+
+void PortPosDlg::raise()
+{
+ int i = listbox->currentItem();
+ arts_debug("selected %d",i);
+ if(i < 0) return;
+
+ StructurePort *port = listports[i];
+ assert(port);
+
+ // hmm ok this is ugly that the raise function calls lowerPosition
+ port->lowerPosition();
+ update();
+
+ unsigned long l;
+ for(l=0;l<listports.size();l++)
+ if(listports[l]->id() == port->id())
+ listbox->setCurrentItem(l);
+}
+
+void PortPosDlg::lower()
+{
+ int i = listbox->currentItem();
+ arts_debug("selected %d",i);
+ if(i < 0) return;
+ StructurePort *port = listports[i];
+ assert(port);
+
+ port->raisePosition();
+ update();
+
+ unsigned long l;
+ for(l=0;l<listports.size();l++)
+ if(listports[l]->id() == port->id())
+ listbox->setCurrentItem(l);
+}
+
+void PortPosDlg::rename()
+{
+ int i = listbox->currentItem();
+ arts_debug("selected %d",i);
+ if(i < 0) return;
+ StructurePort *port = listports[i];
+ assert(port);
+
+ bool ok;
+ QString name = KInputDialog::getText( i18n( "Rename Port" ),
+ i18n( "Enter port name:" ), port->name(), &ok, this );
+ if (ok)
+ {
+ arts_debug("rename OK...");
+ port->rename(name.local8Bit());
+ }
+ update();
+
+ unsigned long l;
+ for(l=0;l<listports.size();l++)
+ if(listports[l]->id() == port->id())
+ listbox->setCurrentItem(l);
+}
+void PortPosDlg::update()
+{
+ list<StructureComponent *> &cl = *structure->getComponentList();
+ list<StructureComponent *>::iterator ci;
+
+ listports.erase(listports.begin(), listports.end());
+ listbox->clear();
+
+ // first incoming ports, then outgoing (which are represented by
+ // the opposite directions inside the structure)
+ for(int direction = 0; direction < 2; direction++)
+ {
+ map<long, StructurePort *> pmap;
+ int finddirection = ModulePort::in;
+ int pcount = 0;
+
+ if(direction == 0) finddirection = ModulePort::out;
+
+ for(ci = cl.begin(); ci != cl.end(); ++ci)
+ {
+ StructureComponent *component = *ci;
+ if(component->type() == StructureComponent::ctPort)
+ {
+ StructurePort *port = (StructurePort *)component;
+ if(port->port()->direction == finddirection)
+ {
+ arts_debug("port %s position %ld",
+ port->name().local8Bit().data(), port->position());
+ pmap[port->position()] = port;
+ pcount++;
+ }
+ }
+ }
+ for(int i=0;i<pcount;i++)
+ {
+ StructurePort *port = pmap[i];
+ if (port)
+ {
+ assert(port);
+ listbox->insertItem(port->name(),listports.size());
+ listports.push_back(port);
+ arts_debug("listports.size() is now %d",listports.size());
+ }
+ }
+ }
+ listbox->repaint();
+}
+
+void PortPosDlg::help()
+{
+ KApplication::kApplication()->invokeHelp("", "karts");
+}
+
+#include "portposdlg.moc"
diff --git a/arts/builder/portposdlg.h b/arts/builder/portposdlg.h
new file mode 100644
index 00000000..e9c8f855
--- /dev/null
+++ b/arts/builder/portposdlg.h
@@ -0,0 +1,51 @@
+ /*
+
+ Copyright (C) 1998-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.
+
+ */
+
+#ifndef __PORTPOSDLG_H_
+#define __PORTPOSDLG_H_
+
+#include "structure.h"
+#include "structureport.h"
+#include <qdialog.h>
+#include <qlistbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <vector>
+
+class PortPosDlg :public QDialog {
+ Q_OBJECT
+protected:
+ Structure *structure;
+ QListBox *listbox;
+
+ std::vector<StructurePort *> listports;
+public:
+ PortPosDlg(QWidget *parent, Structure *structure);
+
+ void update();
+public slots:
+ void raise();
+ void lower();
+ void rename();
+ void help();
+};
+
+#endif
diff --git a/arts/builder/propertypanel.cpp b/arts/builder/propertypanel.cpp
new file mode 100644
index 00000000..39c84ac6
--- /dev/null
+++ b/arts/builder/propertypanel.cpp
@@ -0,0 +1,404 @@
+/*
+
+ Copyright (C) 2001 Hans Meine <hans_meine@gmx.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+#include "propertypanel.h"
+#include "propertypanel.moc"
+#include "module.h"
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qcombobox.h>
+#include <qlistbox.h>
+#include <qlineedit.h>
+
+#include <arts/debug.h>
+
+PropertyPanel::PropertyPanel( QWidget* parent, const char* name, WFlags fl )
+ : PropertyPanelBase( parent, name, fl ),
+ component(0L),
+ port(0L)
+{
+ setTitleFont();
+ setTitleColors();
+ connect( kapp, SIGNAL( kdisplayFontChanged() ),
+ this, SLOT( setTitleFont() ));
+ connect( kapp, SIGNAL( kdisplayPaletteChanged() ),
+ this, SLOT( setTitleColors() ));
+ connect( portValueGroup, SIGNAL( clicked(int) ),
+ this, SLOT( pvModeChanged(int) ));
+ connect( constantValueEdit, SIGNAL( returnPressed() ),
+ this, SLOT( writePortProperties() ));
+ connect( constantValueComboBox, SIGNAL( activated(int) ),
+ this, SLOT( writePortProperties() ));
+ connect( portCombo, SIGNAL( activated(int) ),
+ this, SLOT( comboPortSelected(int) ));
+ connect( connectButton, SIGNAL( clicked() ),
+ this, SLOT( connectButtonClicked() ));
+
+ constantValueComboBox->hide();
+ setEnabled( false );
+ tipLabel->hide();
+}
+
+void PropertyPanel::setTitleFont()
+{
+ QFont titleFont = font();
+ titleFont.setPointSizeFloat( titleFont.pointSizeFloat()*1.5f );
+ moduleNameLabel->setFont( titleFont );
+ titleFont = font();
+ titleFont.setPointSizeFloat( titleFont.pointSizeFloat()*1.15f );
+ selectedLabel->setFont( titleFont );
+}
+
+QColorGroup PropertyPanel::highlightColorGroup( QColorGroup cg )
+{
+ cg.setColor( QColorGroup::Foreground, cg.highlightedText() );
+ cg.setColor( QColorGroup::Background, cg.highlight() );
+ return cg;
+}
+
+void PropertyPanel::setTitleColors()
+{
+ QPalette palette = titleFrame->palette();
+ palette.setActive( highlightColorGroup( palette.active() ) );
+ palette.setInactive( highlightColorGroup( palette.inactive() ) );
+ palette.setDisabled( highlightColorGroup( palette.disabled() ) );
+ titleFrame->setPalette( palette );
+}
+
+void PropertyPanel::resizeEvent ( QResizeEvent * )
+{
+ if(width()*3 < height()*4)
+ mainBoxLayout->setDirection( QBoxLayout::TopToBottom );
+ else
+ mainBoxLayout->setDirection( QBoxLayout::LeftToRight );
+}
+
+/*************************************************************/
+
+void PropertyPanel::setSelectedComponent( StructureComponent *component )
+{
+ //kdDebug() << QString("PropertyPanel::setSelectedComponent ") << component << endl;
+ if( this->component == component ) return;
+
+ this->component = component;
+ portCombo->clear();
+ modulePorts.clear();
+ if(!component)
+ setEnabled(false);
+ else
+ {
+ moduleNameLabel->setText( component->name() );
+ if(component->pixmap())
+ {
+ moduleIconLabel->setPixmap( *component->pixmap() );
+ moduleIconLabel->setMinimumSize( moduleIconLabel->sizeHint() );
+ moduleIconLabel->show();
+ }
+ else
+ moduleIconLabel->hide();
+
+ component->dumpPorts(modulePorts);
+
+ // fill combobox
+ for(std::list<ModulePort *>::iterator it = modulePorts.begin();
+ it != modulePorts.end(); it++)
+ {
+ QString portTitle = (*it)->description
+ + QString(" (%1)").arg( (*it)->PortDesc.type().direction == Arts::output ?
+ i18n("OUTPUT") : i18n("INPUT") );
+ portCombo->insertItem( portTitle );
+ }
+ //portCombo->setMinimumSize( portCombo->sizeHint() );
+ setEnabled(true);
+ }
+}
+
+void PropertyPanel::setSelectedPort( ModulePort *port )
+{
+ if( this->port == port ) return;
+
+// if( this->port ) writePortProperties( false ); // rereading not necessary here
+
+ this->port = port;
+ if(port)
+ {
+ setSelectedComponent( port->owner );
+ rereadPortProperties();
+ portValueGroup->setEnabled( true );
+ QString tipText = i18n("Tip: Just typing numbers or alphabetic characters starts entering constant values.");
+ tipLabel->setText( tipText );
+ tipLabel->show();
+
+ // select port in combobox - bah, should be easier ;-)
+ portCombo->setCurrentItem(
+ portCombo->listBox()->index(
+ portCombo->listBox()->findItem( port->description + " (" ) ) );
+ }
+ else
+ {
+ portValueGroup->setEnabled( false );
+ tipLabel->hide();
+ }
+}
+
+void PropertyPanel::pvModeChanged( int newMode )
+{
+ if(!port) return; // sanity check
+
+ switch( newMode )
+ {
+ case 0:
+ case 1:
+ writePortProperties();
+ break;
+ case 2:
+ ; // connection should already be established
+ }
+}
+
+void PropertyPanel::comboPortSelected( int number )
+{
+ if(!component) return;
+
+ std::list<ModulePort *>::iterator it;
+ for( it = modulePorts.begin();
+ (it != modulePorts.end()) && number > 0; it++, number--)
+ ;
+ setSelectedPort( *it );
+ emit portSelected( *it );
+}
+
+void PropertyPanel::connectButtonClicked()
+{
+ if(!port) return; // sanity check
+
+ pvConnectionButton->setChecked( true );
+ emit startConnection( port );
+}
+
+// this is a slot connected to changed() of the editing stuff
+void PropertyPanel::writePortProperties()
+{
+ writePortProperties( true );
+}
+
+void PropertyPanel::writePortProperties( bool reread )
+{
+ //kdDebug() << QString("PropertyPanel::writePortProperties") << endl;
+ if(!port) return; // sanity check
+
+ bool dirty = false;
+
+ if(!pvConnectionButton->isChecked())
+ {
+ if(port->PortDesc.isConnected())
+ {
+ port->PortDesc.disconnectAll();
+ dirty = true;
+ }
+ }
+
+ if(pvNotSetButton->isChecked() &&
+ (port->PortDesc.isConnected() || port->PortDesc.hasValue()))
+ {
+ port->PortDesc.hasValue(false);
+ dirty = true;
+ }
+
+ if(pvConstantButton->isChecked())
+ {
+ std::string type = port->PortDesc.type().dataType;
+ QString newvalue = constantValueEdit->text();
+
+ Arts::Any a;
+ a.type = type;
+ Arts::Buffer b;
+ if(type == "float")
+ b.writeFloat(newvalue.toFloat());
+ else if(type == "long")
+ b.writeLong(newvalue.toLong());
+ else if(type == "string")
+ b.writeString(newvalue.local8Bit().data());
+ else if(type == "boolean")
+ {
+ b.writeBool(newvalue.upper() == "TRUE" || newvalue.upper() == "T"
+ || newvalue == "1");
+ }
+ else if(isEnum(type))
+ {
+ b.writeLong(selectedEnumValue(type));
+ }
+
+ if(b.size() > 0)
+ {
+ b.read(a.value, b.size());
+ port->PortDesc.value(a);
+ dirty = true;
+ }
+ }
+
+ if( dirty )
+ emit portPropertiesChanged( port );
+
+ if( reread )
+ rereadPortProperties();
+}
+
+void PropertyPanel::rereadPortProperties()
+{
+ //kdDebug() << QString("PropertyPanel::rereadPortProperties") << endl;
+ if(!port) return; // sanity check
+
+ std::string dataType = port->PortDesc.type().dataType;
+ if(isEnum(dataType))
+ {
+ constantValueEdit->hide();
+ constantValueComboBox->show();
+
+ fillEnumChoices(dataType);
+ }
+ else
+ {
+ constantValueEdit->show();
+ constantValueComboBox->hide();
+ }
+
+ if( port->PortDesc.hasValue() )
+ {
+ pvConstantButton->setChecked( true );
+
+ QString constValue;
+
+ Arts::Any value = port->PortDesc.value();
+ Arts::Buffer b;
+ b.write(value.value);
+
+ if(isEnum(value.type))
+ {
+ long v = b.readLong();
+ constantValueComboBox->setCurrentItem(findEnumIndex(value.type,v));
+ }
+ else
+ {
+ if(value.type == "float")
+ constValue.sprintf("%2.4f", b.readFloat());
+ else if(value.type == "long")
+ constValue.sprintf("%ld", b.readLong());
+ else if(value.type == "string")
+ {
+ std::string s;
+ b.readString(s);
+ constValue = s.c_str();
+ }
+ else if(value.type == "boolean")
+ {
+ if(b.readBool())
+ constValue = "true";
+ else
+ constValue = "false";
+ }
+ else constValue = ("*unknown type* " + value.type).c_str();
+
+ constantValueEdit->setText( constValue );
+ }
+ }
+ else if( port->PortDesc.isConnected() )
+ pvConnectionButton->setChecked( true );
+ else
+ {
+ pvNotSetButton->setChecked( true );
+ constantValueEdit->clear();
+ }
+
+ pvConnectionButton->setEnabled( port->PortDesc.isConnected() );
+}
+
+bool PropertyPanel::eventFilter( QObject *o, QEvent *e )
+{
+ if( port && !constantValueEdit->hasFocus() && (e->type() == QEvent::KeyPress) ) {
+// kdDebug() << QString(" ..is KeyPress") << endl;
+ QString entered = static_cast<QKeyEvent *>(e)->text();
+ bool goodString = entered.length() > 0;
+
+// kdDebug() << QString("pressed '%1'").arg(entered) << endl;
+
+ for( unsigned int i = 0; i < entered.length(); i++)
+ goodString = goodString && entered[i].isLetterOrNumber();
+
+ if( goodString )
+ {
+ pvConstantButton->setChecked( true );
+ constantValueEdit->setText( entered );
+ constantValueEdit->setFocus();
+// kdDebug() << "keyPress used in propPanel" << endl;
+ return TRUE; // eat event
+ }
+ }
+// else
+// kdDebug() << "event type = " << e->type() << " != " << QEvent::KeyPress << endl;
+ return FALSE; // PropertyPanelBase::eventFilter( o, e );
+}
+
+bool PropertyPanel::isEnum(const std::string& type)
+{
+ Arts::InterfaceRepoV2 interfaceRepo = Arts::DynamicCast(Arts::Dispatcher::the()->interfaceRepo());
+ return (interfaceRepo.identifyType(type) == Arts::tiEnum);
+}
+
+void PropertyPanel::fillEnumChoices(const std::string& type)
+{
+ Arts::EnumDef edef =
+ Arts::Dispatcher::the()->interfaceRepo().queryEnum(type);
+
+ constantValueComboBox->clear();
+
+ std::vector<Arts::EnumComponent>::const_iterator eci;
+ for(eci = edef.contents.begin(); eci != edef.contents.end(); ++eci)
+ constantValueComboBox->insertItem(QString::fromUtf8(eci->name.c_str()));
+}
+
+long PropertyPanel::selectedEnumValue(const std::string& type)
+{
+ unsigned int i = (unsigned int)constantValueComboBox->currentItem();
+ Arts::EnumDef edef =
+ Arts::Dispatcher::the()->interfaceRepo().queryEnum(type);
+
+ if(i >= edef.contents.size()) i = 0;
+ if(edef.contents.size() == 0) return 0;
+ return edef.contents[i].value;
+}
+
+int PropertyPanel::findEnumIndex(const std::string& type, long value)
+{
+ Arts::EnumDef edef =
+ Arts::Dispatcher::the()->interfaceRepo().queryEnum(type);
+
+ for(unsigned int i = 0; i < edef.contents.size(); i++)
+ if(edef.contents[i].value == value)
+ return i;
+ return 0;
+}
diff --git a/arts/builder/propertypanel.h b/arts/builder/propertypanel.h
new file mode 100644
index 00000000..90e1b171
--- /dev/null
+++ b/arts/builder/propertypanel.h
@@ -0,0 +1,78 @@
+/*
+
+ Copyright (C) 2001 Hans Meine <hans_meine@gmx.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+#ifndef PROPERTYPANEL_H
+#define PROPERTYPANEL_H
+
+#include "propertypanelbase.h"
+#include "qpalette.h"
+
+#include <vector>
+#include <list>
+#include <string>
+
+class StructureComponent;
+class ModulePort;
+
+class PropertyPanel: public PropertyPanelBase
+{
+ Q_OBJECT
+
+public:
+ PropertyPanel( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+
+public slots:
+ void setSelectedComponent( StructureComponent *component );
+ void setSelectedPort( ModulePort *port );
+
+protected slots:
+ void setTitleFont();
+ void setTitleColors();
+
+ void pvModeChanged( int newMode );
+ void comboPortSelected( int number );
+ void connectButtonClicked();
+
+ void writePortProperties(); // default reread-> true
+ void writePortProperties( bool reread );
+ void rereadPortProperties();
+
+ bool eventFilter( QObject *, QEvent * );
+
+signals:
+ void startConnection( ModulePort * );
+ void portSelected( ModulePort * );
+ void portPropertiesChanged( ModulePort * ); // might be emitted a little bit too often (see writePortP..)
+
+protected:
+ enum ConnType { ctNone, ctValue, ctConnection };
+ void resizeEvent ( QResizeEvent * );
+
+ StructureComponent *component;
+ ModulePort *port;
+ std::list<ModulePort *> modulePorts;
+
+ QColorGroup highlightColorGroup( QColorGroup cg );
+ bool isEnum(const std::string& type);
+ void fillEnumChoices(const std::string& type);
+ long selectedEnumValue(const std::string& type);
+ int findEnumIndex(const std::string& type, long value);
+};
+
+#endif // PROPERTYPANEL_H
diff --git a/arts/builder/propertypanelbase.ui b/arts/builder/propertypanelbase.ui
new file mode 100644
index 00000000..c89abcc6
--- /dev/null
+++ b/arts/builder/propertypanelbase.ui
@@ -0,0 +1,362 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>PropertyPanelBase</class>
+<author>Hans Meine &lt;hans_meine@gmx.net&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>propertyPanelBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>628</width>
+ <height>484</height>
+ </rect>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>titleFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>8</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>selectedLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Properties of selected module/port:</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>spacerLayout</cstring>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>mainBoxLayout</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout17</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>moduleIconLabel</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout16</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>moduleNameLabel</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>portComboLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Port:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>portCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>portCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer28</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>portValueGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Port Value</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>pvNotSetButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Not set</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>pvConstantButton</cstring>
+ </property>
+ <property name="text">
+ <string>Constant &amp;value:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>constantValueComboBox</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>constantValueEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>connectionLayout</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>pvConnectionButton</cstring>
+ </property>
+ <property name="text">
+ <string>From connection</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer13</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>connectButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Connect</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>tipLabel</cstring>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignLeft</set>
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>pvConstantButton</sender>
+ <signal>clicked()</signal>
+ <receiver>constantValueEdit</receiver>
+ <slot>setFocus()</slot>
+ </connection>
+ <connection>
+ <sender>pvConstantButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>constantValueEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>pvConstantButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>constantValueComboBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">setTitleFont()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/arts/builder/qttableview.cpp b/arts/builder/qttableview.cpp
new file mode 100644
index 00000000..7f044d25
--- /dev/null
+++ b/arts/builder/qttableview.cpp
@@ -0,0 +1,2274 @@
+/**********************************************************************
+** $Id$
+**
+** Implementation of QtTableView class
+**
+** Created : 941115
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file contains a class moved out of the Qt GUI Toolkit API. It
+** may be used, distributed and modified without limitation.
+**
+**********************************************************************/
+
+#include "qttableview.h"
+#include "qttableview.moc"
+#ifndef QT_NO_QTTABLEVIEW
+#include "qscrollbar.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include <limits.h>
+
+enum ScrollBarDirtyFlags {
+ verGeometry = 0x01,
+ verSteps = 0x02,
+ verRange = 0x04,
+ verValue = 0x08,
+ horGeometry = 0x10,
+ horSteps = 0x20,
+ horRange = 0x40,
+ horValue = 0x80,
+ verMask = 0x0F,
+ horMask = 0xF0
+};
+
+
+#define HSBEXT horizontalScrollBar()->sizeHint().height()
+#define VSBEXT verticalScrollBar()->sizeHint().width()
+
+
+class QCornerSquare : public QWidget // internal class
+{
+public:
+ QCornerSquare( QWidget *, const char* = 0 );
+ void paintEvent( QPaintEvent * );
+};
+
+QCornerSquare::QCornerSquare( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+}
+
+void QCornerSquare::paintEvent( QPaintEvent * )
+{
+}
+
+
+// NOT REVISED
+/*!
+ \class QtTableView qttableview.h
+ \brief The QtTableView class provides an abstract base for tables.
+
+ \obsolete
+
+ A table view consists of a number of abstract cells organized in rows
+ and columns, and a visible part called a view. The cells are identified
+ with a row index and a column index. The top-left cell is in row 0,
+ column 0.
+
+ The behavior of the widget can be finely tuned using
+ setTableFlags(); a typical subclass will consist of little more than a
+ call to setTableFlags(), some table content manipulation and an
+ implementation of paintCell(). Subclasses that need cells with
+ variable width or height must reimplement cellHeight() and/or
+ cellWidth(). Use updateTableSize() to tell QtTableView when the
+ width or height has changed.
+
+ When you read this documentation, it is important to understand the
+ distinctions among the four pixel coordinate systems involved.
+
+ \list 1
+ \i The \e cell coordinates. (0,0) is the top-left corner of a cell.
+ Cell coordinates are used by functions such as paintCell().
+
+ \i The \e table coordinates. (0,0) is the top-left corner of the cell at
+ row 0 and column 0. These coordinates are absolute; that is, they are
+ independent of what part of the table is visible at the moment. They are
+ used by functions such as setXOffset() or maxYOffset().
+
+ \i The \e widget coordinates. (0,0) is the top-left corner of the widget,
+ \e including the frame. They are used by functions such as repaint().
+
+ \i The \e view coordinates. (0,0) is the top-left corner of the view, \e
+ excluding the frame. This is the least-used coordinate system; it is used by
+ functions such as viewWidth(). \endlist
+
+ It is rather unfortunate that we have to use four different
+ coordinate systems, but there was no alternative to provide a flexible and
+ powerful base class.
+
+ Note: The row,column indices are always given in that order,
+ i.e., first the vertical (row), then the horizontal (column). This is
+ the opposite order of all pixel operations, which take first the
+ horizontal (x) and then the vertical (y).
+
+ <img src=qtablevw-m.png> <img src=qtablevw-w.png>
+
+ \warning the functions setNumRows(), setNumCols(), setCellHeight(),
+ setCellWidth(), setTableFlags() and clearTableFlags() may cause
+ virtual functions such as cellWidth() and cellHeight() to be called,
+ even if autoUpdate() is FALSE. This may cause errors if relevant
+ state variables are not initialized.
+
+ \warning Experience has shown that use of this widget tends to cause
+ more bugs than expected and our analysis indicates that the widget's
+ very flexibility is the problem. If QScrollView or QListBox can
+ easily be made to do the job you need, we recommend subclassing
+ those widgets rather than QtTableView. In addition, QScrollView makes
+ it easy to have child widgets inside tables, which QtTableView
+ doesn't support at all.
+
+ \sa QScrollView
+ \link guibooks.html#fowler GUI Design Handbook: Table\endlink
+*/
+
+
+/*!
+ Constructs a table view. The \a parent, \a name and \f arguments
+ are passed to the QFrame constructor.
+
+ The \link setTableFlags() table flags\endlink are all cleared (set to 0).
+ Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll
+ bars and \c Tbl_clipCellPainting to get safe clipping.
+
+ The \link setCellHeight() cell height\endlink and \link setCellWidth()
+ cell width\endlink are set to 0.
+
+ Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed;
+ see QFrame::setFrameStyle().
+
+ Note that the \a f argument is \e not \link setTableFlags() table
+ flags \endlink but rather \link QWidget::QWidget() widget
+ flags. \endlink
+
+*/
+
+QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f )
+{
+ nRows = nCols = 0; // zero rows/cols
+ xCellOffs = yCellOffs = 0; // zero offset
+ xCellDelta = yCellDelta = 0; // zero cell offset
+ xOffs = yOffs = 0; // zero total pixel offset
+ cellH = cellW = 0; // user defined cell size
+ tFlags = 0;
+ vScrollBar = hScrollBar = 0; // no scroll bars
+ cornerSquare = 0;
+ sbDirty = 0;
+ eraseInPaint = FALSE;
+ verSliding = FALSE;
+ verSnappingOff = FALSE;
+ horSliding = FALSE;
+ horSnappingOff = FALSE;
+ coveringCornerSquare = FALSE;
+ inSbUpdate = FALSE;
+}
+
+/*!
+ Destroys the table view.
+*/
+
+QtTableView::~QtTableView()
+{
+ delete vScrollBar;
+ delete hScrollBar;
+ delete cornerSquare;
+}
+
+
+/*!
+ \internal
+ Reimplements QWidget::setBackgroundColor() for binary compatibility.
+ \sa setPalette()
+*/
+
+void QtTableView::setBackgroundColor( const QColor &c )
+{
+ QWidget::setBackgroundColor( c );
+}
+
+/*!\reimp
+*/
+
+void QtTableView::setPalette( const QPalette &p )
+{
+ QWidget::setPalette( p );
+}
+
+/*!\reimp
+*/
+
+void QtTableView::show()
+{
+ showOrHideScrollBars();
+ QWidget::show();
+}
+
+
+/*!
+ \overload void QtTableView::repaint( bool erase )
+ Repaints the entire view.
+*/
+
+/*!
+ Repaints the table view directly by calling paintEvent() directly
+ unless updates are disabled.
+
+ Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a
+ (x,y) are in \e widget coordinates.
+
+ If \a w is negative, it is replaced with <code>width() - x</code>.
+ If \a h is negative, it is replaced with <code>height() - y</code>.
+
+ Doing a repaint() usually is faster than doing an update(), but
+ calling update() many times in a row will generate a single paint
+ event.
+
+ At present, QtTableView is the only widget that reimplements \link
+ QWidget::repaint() repaint()\endlink. It does this because by
+ clearing and then repainting one cell at at time, it can make the
+ screen flicker less than it would otherwise. */
+
+void QtTableView::repaint( int x, int y, int w, int h, bool erase )
+{
+ if ( !isVisible() || testWState(WState_BlockUpdates) )
+ return;
+ if ( w < 0 )
+ w = width() - x;
+ if ( h < 0 )
+ h = height() - y;
+ QRect r( x, y, w, h );
+ if ( r.isEmpty() )
+ return; // nothing to do
+ QPaintEvent e( r );
+ if ( erase && backgroundMode() != NoBackground )
+ eraseInPaint = TRUE; // erase when painting
+ paintEvent( &e );
+ eraseInPaint = FALSE;
+}
+
+/*!
+ \overload void QtTableView::repaint( const QRect &r, bool erase )
+ Replaints rectangle \a r. If \a erase is TRUE draws the background
+ using the palette's background.
+*/
+
+
+/*!
+ \fn int QtTableView::numRows() const
+ Returns the number of rows in the table.
+ \sa numCols(), setNumRows()
+*/
+
+/*!
+ Sets the number of rows of the table to \a rows (must be non-negative).
+ Does not change topCell().
+
+ The table repaints itself automatically if autoUpdate() is set.
+
+ \sa numCols(), setNumCols(), numRows()
+*/
+
+void QtTableView::setNumRows( int rows )
+{
+ if ( rows < 0 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.",
+ name( "unnamed" ), rows );
+#endif
+ return;
+ }
+ if ( nRows == rows )
+ return;
+
+ if ( autoUpdate() && isVisible() ) {
+ int oldLastVisible = lastRowVisible();
+ int oldTopCell = topCell();
+ nRows = rows;
+ if ( autoUpdate() && isVisible() &&
+ ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) )
+ repaint( oldTopCell != topCell() );
+ } else {
+ // Be more careful - if destructing, bad things might happen.
+ nRows = rows;
+ }
+ updateScrollBars( verRange );
+ updateFrameSize();
+}
+
+/*!
+ \fn int QtTableView::numCols() const
+ Returns the number of columns in the table.
+ \sa numRows(), setNumCols()
+*/
+
+/*!
+ Sets the number of columns of the table to \a cols (must be non-negative).
+ Does not change leftCell().
+
+ The table repaints itself automatically if autoUpdate() is set.
+
+ \sa numCols(), numRows(), setNumRows()
+*/
+
+void QtTableView::setNumCols( int cols )
+{
+ if ( cols < 0 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.",
+ name( "unnamed" ), cols );
+#endif
+ return;
+ }
+ if ( nCols == cols )
+ return;
+ int oldCols = nCols;
+ nCols = cols;
+ if ( autoUpdate() && isVisible() ) {
+ int maxCol = lastColVisible();
+ if ( maxCol >= oldCols || maxCol >= nCols )
+ repaint();
+ }
+ updateScrollBars( horRange );
+ updateFrameSize();
+}
+
+
+/*!
+ \fn int QtTableView::topCell() const
+ Returns the index of the first row in the table that is visible in
+ the view. The index of the first row is 0.
+ \sa leftCell(), setTopCell()
+*/
+
+/*!
+ Scrolls the table so that \a row becomes the top row.
+ The index of the very first row is 0.
+ \sa setYOffset(), setTopLeftCell(), setLeftCell()
+*/
+
+void QtTableView::setTopCell( int row )
+{
+ setTopLeftCell( row, -1 );
+ return;
+}
+
+/*!
+ \fn int QtTableView::leftCell() const
+ Returns the index of the first column in the table that is visible in
+ the view. The index of the very leftmost column is 0.
+ \sa topCell(), setLeftCell()
+*/
+
+/*!
+ Scrolls the table so that \a col becomes the leftmost
+ column. The index of the leftmost column is 0.
+ \sa setXOffset(), setTopLeftCell(), setTopCell()
+*/
+
+void QtTableView::setLeftCell( int col )
+{
+ setTopLeftCell( -1, col );
+ return;
+}
+
+/*!
+ Scrolls the table so that the cell at row \a row and colum \a
+ col becomes the top-left cell in the view. The cell at the extreme
+ top left of the table is at position (0,0).
+ \sa setLeftCell(), setTopCell(), setOffset()
+*/
+
+void QtTableView::setTopLeftCell( int row, int col )
+{
+ int newX = xOffs;
+ int newY = yOffs;
+
+ if ( col >= 0 ) {
+ if ( cellW ) {
+ newX = col*cellW;
+ if ( newX > maxXOffset() )
+ newX = maxXOffset();
+ } else {
+ newX = 0;
+ while ( col )
+ newX += cellWidth( --col ); // optimize using current! ###
+ }
+ }
+ if ( row >= 0 ) {
+ if ( cellH ) {
+ newY = row*cellH;
+ if ( newY > maxYOffset() )
+ newY = maxYOffset();
+ } else {
+ newY = 0;
+ while ( row )
+ newY += cellHeight( --row ); // optimize using current! ###
+ }
+ }
+ setOffset( newX, newY );
+}
+
+
+/*!
+ \fn int QtTableView::xOffset() const
+
+ Returns the x coordinate in \e table coordinates of the pixel that is
+ currently on the left edge of the view.
+
+ \sa setXOffset(), yOffset(), leftCell() */
+
+/*!
+ Scrolls the table so that \a x becomes the leftmost pixel in the view.
+ The \a x parameter is in \e table coordinates.
+
+ The interaction with \link setTableFlags() Tbl_snapToHGrid
+ \endlink is tricky.
+
+ \sa xOffset(), setYOffset(), setOffset(), setLeftCell()
+*/
+
+void QtTableView::setXOffset( int x )
+{
+ setOffset( x, yOffset() );
+}
+
+/*!
+ \fn int QtTableView::yOffset() const
+
+ Returns the y coordinate in \e table coordinates of the pixel that is
+ currently on the top edge of the view.
+
+ \sa setYOffset(), xOffset(), topCell()
+*/
+
+
+/*!
+ Scrolls the table so that \a y becomes the top pixel in the view.
+ The \a y parameter is in \e table coordinates.
+
+ The interaction with \link setTableFlags() Tbl_snapToVGrid
+ \endlink is tricky.
+
+ \sa yOffset(), setXOffset(), setOffset(), setTopCell()
+*/
+
+void QtTableView::setYOffset( int y )
+{
+ setOffset( xOffset(), y );
+}
+
+/*!
+ Scrolls the table so that \a (x,y) becomes the top-left pixel
+ in the view. Parameters \a (x,y) are in \e table coordinates.
+
+ The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink
+ is tricky. If \a updateScrBars is TRUE, the scroll bars are
+ updated.
+
+ \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell()
+*/
+
+void QtTableView::setOffset( int x, int y, bool updateScrBars )
+{
+ if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) &&
+ (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) &&
+ (x == xOffs && y == yOffs) )
+ return;
+
+ if ( x < 0 )
+ x = 0;
+ if ( y < 0 )
+ y = 0;
+
+ if ( cellW ) {
+ if ( x > maxXOffset() )
+ x = maxXOffset();
+ xCellOffs = x / cellW;
+ if ( !testTableFlags(Tbl_snapToHGrid) ) {
+ xCellDelta = (short)(x % cellW);
+ } else {
+ x = xCellOffs*cellW;
+ xCellDelta = 0;
+ }
+ } else {
+ int xn=0, xcd=0, col = 0;
+ while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) {
+ xn += xcd;
+ col++;
+ }
+ xCellOffs = col;
+ if ( testTableFlags(Tbl_snapToHGrid) ) {
+ xCellDelta = 0;
+ x = xn;
+ } else {
+ xCellDelta = (short)(x-xn);
+ }
+ }
+ if ( cellH ) {
+ if ( y > maxYOffset() )
+ y = maxYOffset();
+ yCellOffs = y / cellH;
+ if ( !testTableFlags(Tbl_snapToVGrid) ) {
+ yCellDelta = (short)(y % cellH);
+ } else {
+ y = yCellOffs*cellH;
+ yCellDelta = 0;
+ }
+ } else {
+ int yn=0, yrd=0, row=0;
+ while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) {
+ yn += yrd;
+ row++;
+ }
+ yCellOffs = row;
+ if ( testTableFlags(Tbl_snapToVGrid) ) {
+ yCellDelta = 0;
+ y = yn;
+ } else {
+ yCellDelta = (short)(y-yn);
+ }
+ }
+ int dx = (x - xOffs);
+ int dy = (y - yOffs);
+ xOffs = x;
+ yOffs = y;
+ if ( autoUpdate() && isVisible() )
+ scroll( dx, dy );
+ if ( updateScrBars )
+ updateScrollBars( verValue | horValue );
+}
+
+
+/*!
+ \overload int QtTableView::cellWidth() const
+
+ Returns the column width in pixels. Returns 0 if the columns have
+ variable widths.
+
+ \sa setCellWidth(), cellHeight()
+*/
+
+/*!
+ Returns the width of column \a col in pixels.
+
+ This function is virtual and must be reimplemented by subclasses that
+ have variable cell widths. Note that if the total table width
+ changes, updateTableSize() must be called.
+
+ \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize()
+*/
+
+int QtTableView::cellWidth( int )
+{
+ return cellW;
+}
+
+
+/*!
+ Sets the width in pixels of the table cells to \a cellWidth.
+
+ Setting it to 0 means that the column width is variable. When
+ set to 0 (this is the default) QtTableView calls the virtual function
+ cellWidth() to get the width.
+
+ \sa cellWidth(), setCellHeight(), totalWidth(), numCols()
+*/
+
+void QtTableView::setCellWidth( int cellWidth )
+{
+ if ( cellW == cellWidth )
+ return;
+#if defined(QT_CHECK_RANGE)
+ if ( cellWidth < 0 || cellWidth > SHRT_MAX ) {
+ qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)",
+ name( "unnamed" ), cellWidth );
+ return;
+ }
+#endif
+ cellW = (short)cellWidth;
+
+ updateScrollBars( horSteps | horRange );
+ if ( autoUpdate() && isVisible() )
+ repaint();
+
+}
+
+/*!
+ \overload int QtTableView::cellHeight() const
+
+ Returns the row height, in pixels. Returns 0 if the rows have
+ variable heights.
+
+ \sa setCellHeight(), cellWidth()
+*/
+
+
+/*!
+ Returns the height of row \a row in pixels.
+
+ This function is virtual and must be reimplemented by subclasses that
+ have variable cell heights. Note that if the total table height
+ changes, updateTableSize() must be called.
+
+ \sa setCellHeight(), cellWidth(), totalHeight()
+*/
+
+int QtTableView::cellHeight( int )
+{
+ return cellH;
+}
+
+/*!
+ Sets the height in pixels of the table cells to \a cellHeight.
+
+ Setting it to 0 means that the row height is variable. When set
+ to 0 (this is the default), QtTableView calls the virtual function
+ cellHeight() to get the height.
+
+ \sa cellHeight(), setCellWidth(), totalHeight(), numRows()
+*/
+
+void QtTableView::setCellHeight( int cellHeight )
+{
+ if ( cellH == cellHeight )
+ return;
+#if defined(QT_CHECK_RANGE)
+ if ( cellHeight < 0 || cellHeight > SHRT_MAX ) {
+ qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)",
+ name( "unnamed" ), cellHeight );
+ return;
+ }
+#endif
+ cellH = (short)cellHeight;
+ if ( autoUpdate() && isVisible() )
+ repaint();
+ updateScrollBars( verSteps | verRange );
+}
+
+
+/*!
+ Returns the total width of the table in pixels.
+
+ This function is virtual and should be reimplemented by subclasses that
+ have variable cell widths and a non-trivial cellWidth() function, or a
+ large number of columns in the table.
+
+ The default implementation may be slow for very wide tables.
+
+ \sa cellWidth(), totalHeight() */
+
+int QtTableView::totalWidth()
+{
+ if ( cellW ) {
+ return cellW*nCols;
+ } else {
+ int tw = 0;
+ for( int i = 0 ; i < nCols ; i++ )
+ tw += cellWidth( i );
+ return tw;
+ }
+}
+
+/*!
+ Returns the total height of the table in pixels.
+
+ This function is virtual and should be reimplemented by subclasses that
+ have variable cell heights and a non-trivial cellHeight() function, or a
+ large number of rows in the table.
+
+ The default implementation may be slow for very tall tables.
+
+ \sa cellHeight(), totalWidth()
+*/
+
+int QtTableView::totalHeight()
+{
+ if ( cellH ) {
+ return cellH*nRows;
+ } else {
+ int th = 0;
+ for( int i = 0 ; i < nRows ; i++ )
+ th += cellHeight( i );
+ return th;
+ }
+}
+
+
+/*!
+ \fn uint QtTableView::tableFlags() const
+
+ Returns the union of the table flags that are currently set.
+
+ \sa setTableFlags(), clearTableFlags(), testTableFlags()
+*/
+
+/*!
+ \fn bool QtTableView::testTableFlags( uint f ) const
+
+ Returns TRUE if any of the table flags in \a f are currently set,
+ otherwise FALSE.
+
+ \sa setTableFlags(), clearTableFlags(), tableFlags()
+*/
+
+/*!
+ Sets the table flags to \a f.
+
+ If a flag setting changes the appearance of the table, the table is
+ repainted if - and only if - autoUpdate() is TRUE.
+
+ The table flags are mostly single bits, though there are some multibit
+ flags for convenience. Here is a complete list:
+
+ <dl compact>
+ <dt> Tbl_vScrollBar <dd> - The table has a vertical scroll bar.
+ <dt> Tbl_hScrollBar <dd> - The table has a horizontal scroll bar.
+ <dt> Tbl_autoVScrollBar <dd> - The table has a vertical scroll bar if
+ - and only if - the table is taller than the view.
+ <dt> Tbl_autoHScrollBar <dd> The table has a horizontal scroll bar if
+ - and only if - the table is wider than the view.
+ <dt> Tbl_autoScrollBars <dd> - The union of the previous two flags.
+ <dt> Tbl_clipCellPainting <dd> - The table uses QPainter::setClipRect() to
+ make sure that paintCell() will not draw outside the cell
+ boundaries.
+ <dt> Tbl_cutCellsV <dd> - The table will never show part of a
+ cell at the bottom of the table; if there is not space for all of
+ a cell, the space is left blank.
+ <dt> Tbl_cutCellsH <dd> - The table will never show part of a
+ cell at the right side of the table; if there is not space for all of
+ a cell, the space is left blank.
+ <dt> Tbl_cutCells <dd> - The union of the previous two flags.
+ <dt> Tbl_scrollLastHCell <dd> - When the user scrolls horizontally,
+ let him/her scroll the last cell left until it is at the left
+ edge of the view. If this flag is not set, the user can only scroll
+ to the point where the last cell is completely visible.
+ <dt> Tbl_scrollLastVCell <dd> - When the user scrolls vertically, let
+ him/her scroll the last cell up until it is at the top edge of
+ the view. If this flag is not set, the user can only scroll to the
+ point where the last cell is completely visible.
+ <dt> Tbl_scrollLastCell <dd> - The union of the previous two flags.
+ <dt> Tbl_smoothHScrolling <dd> - The table scrolls as smoothly as
+ possible when the user scrolls horizontally. When this flag is not
+ set, scrolling is done one cell at a time.
+ <dt> Tbl_smoothVScrolling <dd> - The table scrolls as smoothly as
+ possible when scrolling vertically. When this flag is not set,
+ scrolling is done one cell at a time.
+ <dt> Tbl_smoothScrolling <dd> - The union of the previous two flags.
+ <dt> Tbl_snapToHGrid <dd> - Except when the user is actually scrolling,
+ the leftmost column shown snaps to the leftmost edge of the view.
+ <dt> Tbl_snapToVGrid <dd> - Except when the user is actually
+ scrolling, the top row snaps to the top edge of the view.
+ <dt> Tbl_snapToGrid <dd> - The union of the previous two flags.
+ </dl>
+
+ You can specify more than one flag at a time using bitwise OR.
+
+ Example:
+ \code
+ setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars );
+ \endcode
+
+ \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and
+ Tbl_cutCellsV) may cause painting problems when scrollbars are
+ enabled. Do not combine cutCells and scrollbars.
+
+
+ \sa clearTableFlags(), testTableFlags(), tableFlags()
+*/
+
+void QtTableView::setTableFlags( uint f )
+{
+ f = (f ^ tFlags) & f; // clear flags already set
+ tFlags |= f;
+
+ bool updateOn = autoUpdate();
+ setAutoUpdate( FALSE );
+
+ uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
+
+ if ( f & Tbl_vScrollBar ) {
+ setVerScrollBar( TRUE );
+ }
+ if ( f & Tbl_hScrollBar ) {
+ setHorScrollBar( TRUE );
+ }
+ if ( f & Tbl_autoVScrollBar ) {
+ updateScrollBars( verRange );
+ }
+ if ( f & Tbl_autoHScrollBar ) {
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_scrollLastHCell ) {
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_scrollLastVCell ) {
+ updateScrollBars( verRange );
+ }
+ if ( f & Tbl_snapToHGrid ) {
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_snapToVGrid ) {
+ updateScrollBars( verRange );
+ }
+ if ( f & Tbl_snapToGrid ) { // Note: checks for 2 flags
+ if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll?
+ (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) {
+ snapToGrid( (f & Tbl_snapToHGrid) != 0, // do snapping
+ (f & Tbl_snapToVGrid) != 0 );
+ repaintMask |= Tbl_snapToGrid; // repaint table
+ }
+ }
+
+ if ( updateOn ) {
+ setAutoUpdate( TRUE );
+ updateScrollBars();
+ if ( isVisible() && (f & repaintMask) )
+ repaint();
+ }
+
+}
+
+/*!
+ Clears the \link setTableFlags() table flags\endlink that are set
+ in \a f.
+
+ Example (clears a single flag):
+ \code
+ clearTableFlags( Tbl_snapToGrid );
+ \endcode
+
+ The default argument clears all flags.
+
+ \sa setTableFlags(), testTableFlags(), tableFlags()
+*/
+
+void QtTableView::clearTableFlags( uint f )
+{
+ f = (f ^ ~tFlags) & f; // clear flags that are already 0
+ tFlags &= ~f;
+
+ bool updateOn = autoUpdate();
+ setAutoUpdate( FALSE );
+
+ uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
+
+ if ( f & Tbl_vScrollBar ) {
+ setVerScrollBar( FALSE );
+ }
+ if ( f & Tbl_hScrollBar ) {
+ setHorScrollBar( FALSE );
+ }
+ if ( f & Tbl_scrollLastHCell ) {
+ int maxX = maxXOffset();
+ if ( xOffs > maxX ) {
+ setOffset( maxX, yOffs );
+ repaintMask |= Tbl_scrollLastHCell;
+ }
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_scrollLastVCell ) {
+ int maxY = maxYOffset();
+ if ( yOffs > maxY ) {
+ setOffset( xOffs, maxY );
+ repaintMask |= Tbl_scrollLastVCell;
+ }
+ updateScrollBars( verRange );
+ }
+ if ( f & Tbl_smoothScrolling ) { // Note: checks for 2 flags
+ if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll?
+ (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) {
+ snapToGrid( (f & Tbl_smoothHScrolling) != 0, // do snapping
+ (f & Tbl_smoothVScrolling) != 0 );
+ repaintMask |= Tbl_smoothScrolling; // repaint table
+ }
+ }
+ if ( f & Tbl_snapToHGrid ) {
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_snapToVGrid ) {
+ updateScrollBars( verRange );
+ }
+ if ( updateOn ) {
+ setAutoUpdate( TRUE );
+ updateScrollBars(); // returns immediately if nothing to do
+ if ( isVisible() && (f & repaintMask) )
+ repaint();
+ }
+
+}
+
+
+/*!
+ \fn bool QtTableView::autoUpdate() const
+
+ Returns TRUE if the view updates itself automatically whenever it
+ is changed in some way.
+
+ \sa setAutoUpdate()
+*/
+
+/*!
+ Sets the auto-update option of the table view to \a enable.
+
+ If \a enable is TRUE (this is the default), the view updates itself
+ automatically whenever it has changed in some way (for example, when a
+ \link setTableFlags() flag\endlink is changed).
+
+ If \a enable is FALSE, the view does NOT repaint itself or update
+ its internal state variables when it is changed. This can be
+ useful to avoid flicker during large changes and is singularly
+ useless otherwise. Disable auto-update, do the changes, re-enable
+ auto-update and call repaint().
+
+ \warning Do not leave the view in this state for a long time
+ (i.e., between events). If, for example, the user interacts with the
+ view when auto-update is off, strange things can happen.
+
+ Setting auto-update to TRUE does not repaint the view; you must call
+ repaint() to do this.
+
+ \sa autoUpdate(), repaint()
+*/
+
+void QtTableView::setAutoUpdate( bool enable )
+{
+ if ( isUpdatesEnabled() == enable )
+ return;
+ setUpdatesEnabled( enable );
+ if ( enable ) {
+ showOrHideScrollBars();
+ updateScrollBars();
+ }
+}
+
+
+/*!
+ Repaints the cell at row \a row, column \a col if it is inside the view.
+
+ If \a erase is TRUE, the relevant part of the view is cleared to the
+ background color/pixmap before the contents are repainted.
+
+ \sa isVisible()
+*/
+
+void QtTableView::updateCell( int row, int col, bool erase )
+{
+ int xPos, yPos;
+ if ( !colXPos( col, &xPos ) )
+ return;
+ if ( !rowYPos( row, &yPos ) )
+ return;
+ QRect uR = QRect( xPos, yPos,
+ cellW ? cellW : cellWidth(col),
+ cellH ? cellH : cellHeight(row) );
+ repaint( uR.intersect(viewRect()), erase );
+}
+
+
+/*!
+ \fn QRect QtTableView::cellUpdateRect() const
+
+ This function should be called only from the paintCell() function in
+ subclasses. It returns the portion of a cell that actually needs to be
+ updated in \e cell coordinates. This is useful only for non-trivial
+ paintCell().
+
+*/
+
+/*!
+ Returns the rectangle that is the actual table, excluding any
+ frame, in \e widget coordinates.
+*/
+
+QRect QtTableView::viewRect() const
+{
+ return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() );
+}
+
+
+/*!
+ Returns the index of the last (bottom) row in the view.
+ The index of the first row is 0.
+
+ If no rows are visible it returns -1. This can happen if the
+ view is too small for the first row and Tbl_cutCellsV is set.
+
+ \sa lastColVisible()
+*/
+
+int QtTableView::lastRowVisible() const
+{
+ int cellMaxY;
+ int row = findRawRow( maxViewY(), &cellMaxY );
+ if ( row == -1 || row >= nRows ) { // maxViewY() past end?
+ row = nRows - 1; // yes: return last row
+ } else {
+ if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) {
+ if ( row == yCellOffs ) // cut by right margin?
+ return -1; // yes, nothing in the view
+ else
+ row = row - 1; // cut by margin, one back
+ }
+ }
+ return row;
+}
+
+/*!
+ Returns the index of the last (right) column in the view.
+ The index of the first column is 0.
+
+ If no columns are visible it returns -1. This can happen if the
+ view is too narrow for the first column and Tbl_cutCellsH is set.
+
+ \sa lastRowVisible()
+*/
+
+int QtTableView::lastColVisible() const
+{
+ int cellMaxX;
+ int col = findRawCol( maxViewX(), &cellMaxX );
+ if ( col == -1 || col >= nCols ) { // maxViewX() past end?
+ col = nCols - 1; // yes: return last col
+ } else {
+ if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) {
+ if ( col == xCellOffs ) // cut by bottom margin?
+ return -1; // yes, nothing in the view
+ else
+ col = col - 1; // cell by margin, one back
+ }
+ }
+ return col;
+}
+
+/*!
+ Returns TRUE if \a row is at least partially visible.
+ \sa colIsVisible()
+*/
+
+bool QtTableView::rowIsVisible( int row ) const
+{
+ return rowYPos( row, 0 );
+}
+
+/*!
+ Returns TRUE if \a col is at least partially visible.
+ \sa rowIsVisible()
+*/
+
+bool QtTableView::colIsVisible( int col ) const
+{
+ return colXPos( col, 0 );
+}
+
+
+/*!
+ \internal
+ Called when both scroll bars are active at the same time. Covers the
+ bottom left corner between the two scroll bars with an empty widget.
+*/
+
+void QtTableView::coverCornerSquare( bool enable )
+{
+ coveringCornerSquare = enable;
+ if ( !cornerSquare && enable ) {
+ cornerSquare = new QCornerSquare( this );
+ Q_CHECK_PTR( cornerSquare );
+ cornerSquare->setGeometry( maxViewX() + frameWidth() + 1,
+ maxViewY() + frameWidth() + 1,
+ VSBEXT,
+ HSBEXT);
+ }
+ if ( autoUpdate() && cornerSquare ) {
+ if ( enable )
+ cornerSquare->show();
+ else
+ cornerSquare->hide();
+ }
+}
+
+
+/*!
+ \internal
+ Scroll the view to a position such that:
+
+ If \a horizontal is TRUE, the leftmost column shown fits snugly
+ with the left edge of the view.
+
+ If \a vertical is TRUE, the top row shown fits snugly with the top
+ of the view.
+
+ You can achieve the same effect automatically by setting any of the
+ \link setTableFlags() Tbl_snapTo*Grid \endlink table flags.
+*/
+
+void QtTableView::snapToGrid( bool horizontal, bool vertical )
+{
+ int newXCell = -1;
+ int newYCell = -1;
+ if ( horizontal && xCellDelta != 0 ) {
+ int w = cellW ? cellW : cellWidth( xCellOffs );
+ if ( xCellDelta >= w/2 )
+ newXCell = xCellOffs + 1;
+ else
+ newXCell = xCellOffs;
+ }
+ if ( vertical && yCellDelta != 0 ) {
+ int h = cellH ? cellH : cellHeight( yCellOffs );
+ if ( yCellDelta >= h/2 )
+ newYCell = yCellOffs + 1;
+ else
+ newYCell = yCellOffs;
+ }
+ setTopLeftCell( newYCell, newXCell ); //row,column
+}
+
+/*!
+ \internal
+ This internal slot is connected to the horizontal scroll bar's
+ QScrollBar::valueChanged() signal.
+
+ Moves the table horizontally to offset \a val without updating the
+ scroll bar.
+*/
+
+void QtTableView::horSbValue( int val )
+{
+ if ( horSliding ) {
+ horSliding = FALSE;
+ if ( horSnappingOff ) {
+ horSnappingOff = FALSE;
+ tFlags |= Tbl_snapToHGrid;
+ }
+ }
+ setOffset( val, yOffs, FALSE );
+}
+
+/*!
+ \internal
+ This internal slot is connected to the horizontal scroll bar's
+ QScrollBar::sliderMoved() signal.
+
+ Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set.
+*/
+
+void QtTableView::horSbSliding( int val )
+{
+ if ( testTableFlags(Tbl_snapToHGrid) &&
+ testTableFlags(Tbl_smoothHScrolling) ) {
+ tFlags &= ~Tbl_snapToHGrid; // turn off snapping while sliding
+ setOffset( val, yOffs, FALSE );
+ tFlags |= Tbl_snapToHGrid; // turn on snapping again
+ } else {
+ setOffset( val, yOffs, FALSE );
+ }
+}
+
+/*!
+ \internal
+ This internal slot is connected to the horizontal scroll bar's
+ QScrollBar::sliderReleased() signal.
+*/
+
+void QtTableView::horSbSlidingDone( )
+{
+ if ( testTableFlags(Tbl_snapToHGrid) &&
+ testTableFlags(Tbl_smoothHScrolling) )
+ snapToGrid( TRUE, FALSE );
+}
+
+/*!
+ \internal
+ This internal slot is connected to the vertical scroll bar's
+ QScrollBar::valueChanged() signal.
+
+ Moves the table vertically to offset \a val without updating the
+ scroll bar.
+*/
+
+void QtTableView::verSbValue( int val )
+{
+ if ( verSliding ) {
+ verSliding = FALSE;
+ if ( verSnappingOff ) {
+ verSnappingOff = FALSE;
+ tFlags |= Tbl_snapToVGrid;
+ }
+ }
+ setOffset( xOffs, val, FALSE );
+}
+
+/*!
+ \internal
+ This internal slot is connected to the vertical scroll bar's
+ QScrollBar::sliderMoved() signal.
+
+ Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set.
+*/
+
+void QtTableView::verSbSliding( int val )
+{
+ if ( testTableFlags(Tbl_snapToVGrid) &&
+ testTableFlags(Tbl_smoothVScrolling) ) {
+ tFlags &= ~Tbl_snapToVGrid; // turn off snapping while sliding
+ setOffset( xOffs, val, FALSE );
+ tFlags |= Tbl_snapToVGrid; // turn on snapping again
+ } else {
+ setOffset( xOffs, val, FALSE );
+ }
+}
+
+/*!
+ \internal
+ This internal slot is connected to the vertical scroll bar's
+ QScrollBar::sliderReleased() signal.
+*/
+
+void QtTableView::verSbSlidingDone( )
+{
+ if ( testTableFlags(Tbl_snapToVGrid) &&
+ testTableFlags(Tbl_smoothVScrolling) )
+ snapToGrid( FALSE, TRUE );
+}
+
+
+/*!
+ This virtual function is called before painting of table cells
+ is started. It can be reimplemented by subclasses that want to
+ to set up the painter in a special way and that do not want to
+ do so for each cell.
+*/
+
+void QtTableView::setupPainter( QPainter * )
+{
+}
+
+/*!
+ \fn void QtTableView::paintCell( QPainter *p, int row, int col )
+
+ This pure virtual function is called to paint the single cell at \a
+ (row,col) using \a p, which is open when paintCell() is called and
+ must remain open.
+
+ The coordinate system is \link QPainter::translate() translated \endlink
+ so that the origin is at the top-left corner of the cell to be
+ painted, i.e. \e cell coordinates. Do not scale or shear the coordinate
+ system (or if you do, restore the transformation matrix before you
+ return).
+
+ The painter is not clipped by default and for maximum efficiency. For safety,
+ call setTableFlags(Tbl_clipCellPainting) to enable clipping.
+
+ \sa paintEvent(), setTableFlags() */
+
+
+/*!
+ Handles paint events, \a e, for the table view.
+
+ Calls paintCell() for the cells that needs to be repainted.
+*/
+
+void QtTableView::paintEvent( QPaintEvent *e )
+{
+ QRect updateR = e->rect(); // update rectangle
+ if ( sbDirty ) {
+ bool e = eraseInPaint;
+ updateScrollBars();
+ eraseInPaint = e;
+ }
+
+ QPainter paint( this );
+
+ if ( !contentsRect().contains( updateR, TRUE ) ) {// update frame ?
+ drawFrame( &paint );
+ if ( updateR.left() < frameWidth() ) //###
+ updateR.setLeft( frameWidth() );
+ if ( updateR.top() < frameWidth() )
+ updateR.setTop( frameWidth() );
+ }
+
+ int maxWX = maxViewX();
+ int maxWY = maxViewY();
+ if ( updateR.right() > maxWX )
+ updateR.setRight( maxWX );
+ if ( updateR.bottom() > maxWY )
+ updateR.setBottom( maxWY );
+
+ setupPainter( &paint ); // prepare for painting table
+
+ int firstRow = findRow( updateR.y() );
+ int firstCol = findCol( updateR.x() );
+ int xStart, yStart;
+ if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) {
+ paint.eraseRect( updateR ); // erase area outside cells but in view
+ return;
+ }
+ int maxX = updateR.right();
+ int maxY = updateR.bottom();
+ int row = firstRow;
+ int col;
+ int yPos = yStart;
+ int xPos = maxX+1; // in case the while() is empty
+ int nextX;
+ int nextY;
+ QRect winR = viewRect();
+ QRect cellR;
+ QRect cellUR;
+#ifndef QT_NO_TRANSFORMATIONS
+ QWMatrix matrix;
+#endif
+
+ while ( yPos <= maxY && row < nRows ) {
+ nextY = yPos + (cellH ? cellH : cellHeight( row ));
+ if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) )
+ break;
+ col = firstCol;
+ xPos = xStart;
+ while ( xPos <= maxX && col < nCols ) {
+ nextX = xPos + (cellW ? cellW : cellWidth( col ));
+ if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) )
+ break;
+
+ cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col),
+ cellH ? cellH : cellHeight(row) );
+ cellUR = cellR.intersect( updateR );
+ if ( cellUR.isValid() ) {
+ cellUpdateR = cellUR;
+ cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates
+ if ( eraseInPaint )
+ paint.eraseRect( cellUR );
+
+#ifndef QT_NO_TRANSFORMATIONS
+ matrix.translate( xPos, yPos );
+ paint.setWorldMatrix( matrix );
+ if ( testTableFlags(Tbl_clipCellPainting) ||
+ frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
+ paint.setClipRect( cellUR );
+ paintCell( &paint, row, col );
+ paint.setClipping( FALSE );
+ } else {
+ paintCell( &paint, row, col );
+ }
+ matrix.reset();
+ paint.setWorldMatrix( matrix );
+#else
+ paint.translate( xPos, yPos );
+ if ( testTableFlags(Tbl_clipCellPainting) ||
+ frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
+ paint.setClipRect( cellUR );
+ paintCell( &paint, row, col );
+ paint.setClipping( FALSE );
+ } else {
+ paintCell( &paint, row, col );
+ }
+ paint.translate( -xPos, -yPos );
+#endif
+ }
+ col++;
+ xPos = nextX;
+ }
+ row++;
+ yPos = nextY;
+ }
+
+ // while painting we have to erase any areas in the view that
+ // are not covered by cells but are covered by the paint event
+ // rectangle these must be erased. We know that xPos is the last
+ // x pixel updated + 1 and that yPos is the last y pixel updated + 1.
+
+ // Note that this needs to be done regardless whether we do
+ // eraseInPaint or not. Reason: a subclass may implement
+ // flicker-freeness and encourage the use of repaint(FALSE).
+ // The subclass, however, cannot draw all pixels, just those
+ // inside the cells. So QtTableView is reponsible for all pixels
+ // outside the cells.
+
+ QRect viewR = viewRect();
+ const QColorGroup g = colorGroup();
+
+ if ( xPos <= maxX ) {
+ QRect r = viewR;
+ r.setLeft( xPos );
+ r.setBottom( yPos<maxY?yPos:maxY );
+ if ( inherits( "QMultiLineEdit" ) )
+ paint.fillRect( r.intersect( updateR ), g.base() );
+ else
+ paint.eraseRect( r.intersect( updateR ) );
+ }
+ if ( yPos <= maxY ) {
+ QRect r = viewR;
+ r.setTop( yPos );
+ if ( inherits( "QMultiLineEdit" ) )
+ paint.fillRect( r.intersect( updateR ), g.base() );
+ else
+ paint.eraseRect( r.intersect( updateR ) );
+ }
+}
+
+/*!\reimp
+*/
+void QtTableView::resizeEvent( QResizeEvent * )
+{
+ updateScrollBars( horValue | verValue | horSteps | horGeometry | horRange |
+ verSteps | verGeometry | verRange );
+ showOrHideScrollBars();
+ updateFrameSize();
+ int maxX = QMIN( xOffs, maxXOffset() ); // ### can be slow
+ int maxY = QMIN( yOffs, maxYOffset() );
+ setOffset( maxX, maxY );
+}
+
+
+/*!
+ Redraws all visible cells in the table view.
+*/
+
+void QtTableView::updateView()
+{
+ repaint( viewRect() );
+}
+
+/*!
+ Returns a pointer to the vertical scroll bar mainly so you can
+ connect() to its signals. Note that the scroll bar works in pixel
+ values; use findRow() to translate to cell numbers.
+*/
+
+QScrollBar *QtTableView::verticalScrollBar() const
+{
+ QtTableView *that = (QtTableView*)this; // semantic const
+ if ( !vScrollBar ) {
+ QScrollBar *sb = new QScrollBar( QScrollBar::Vertical, that );
+#ifndef QT_NO_CURSOR
+ sb->setCursor( arrowCursor );
+#endif
+ sb->resize( sb->sizeHint() ); // height is irrelevant
+ Q_CHECK_PTR(sb);
+ sb->setTracking( FALSE );
+ sb->setFocusPolicy( NoFocus );
+ connect( sb, SIGNAL(valueChanged(int)),
+ SLOT(verSbValue(int)));
+ connect( sb, SIGNAL(sliderMoved(int)),
+ SLOT(verSbSliding(int)));
+ connect( sb, SIGNAL(sliderReleased()),
+ SLOT(verSbSlidingDone()));
+ sb->hide();
+ that->vScrollBar = sb;
+ return sb;
+ }
+ return vScrollBar;
+}
+
+/*!
+ Returns a pointer to the horizontal scroll bar mainly so you can
+ connect() to its signals. Note that the scroll bar works in pixel
+ values; use findCol() to translate to cell numbers.
+*/
+
+QScrollBar *QtTableView::horizontalScrollBar() const
+{
+ QtTableView *that = (QtTableView*)this; // semantic const
+ if ( !hScrollBar ) {
+ QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that );
+#ifndef QT_NO_CURSOR
+ sb->setCursor( arrowCursor );
+#endif
+ sb->resize( sb->sizeHint() ); // width is irrelevant
+ sb->setFocusPolicy( NoFocus );
+ Q_CHECK_PTR(sb);
+ sb->setTracking( FALSE );
+ connect( sb, SIGNAL(valueChanged(int)),
+ SLOT(horSbValue(int)));
+ connect( sb, SIGNAL(sliderMoved(int)),
+ SLOT(horSbSliding(int)));
+ connect( sb, SIGNAL(sliderReleased()),
+ SLOT(horSbSlidingDone()));
+ sb->hide();
+ that->hScrollBar = sb;
+ return sb;
+ }
+ return hScrollBar;
+}
+
+/*!
+ Enables or disables the horizontal scroll bar, as required by
+ setAutoUpdate() and the \link setTableFlags() table flags\endlink.
+*/
+
+void QtTableView::setHorScrollBar( bool on, bool update )
+{
+ if ( on ) {
+ tFlags |= Tbl_hScrollBar;
+ horizontalScrollBar(); // created
+ if ( update )
+ updateScrollBars( horMask | verMask );
+ else
+ sbDirty = sbDirty | (horMask | verMask);
+ if ( testTableFlags( Tbl_vScrollBar ) )
+ coverCornerSquare( TRUE );
+ if ( autoUpdate() )
+ sbDirty = sbDirty | horMask;
+ } else {
+ tFlags &= ~Tbl_hScrollBar;
+ if ( !hScrollBar )
+ return;
+ coverCornerSquare( FALSE );
+ bool hideScrollBar = autoUpdate() && hScrollBar->isVisible();
+ if ( hideScrollBar )
+ hScrollBar->hide();
+ if ( update )
+ updateScrollBars( verMask );
+ else
+ sbDirty = sbDirty | verMask;
+ if ( hideScrollBar && isVisible() )
+ repaint( hScrollBar->x(), hScrollBar->y(),
+ width() - hScrollBar->x(), hScrollBar->height() );
+ }
+ if ( update )
+ updateFrameSize();
+}
+
+
+/*!
+ Enables or disables the vertical scroll bar, as required by
+ setAutoUpdate() and the \link setTableFlags() table flags\endlink.
+*/
+
+void QtTableView::setVerScrollBar( bool on, bool update )
+{
+ if ( on ) {
+ tFlags |= Tbl_vScrollBar;
+ verticalScrollBar(); // created
+ if ( update )
+ updateScrollBars( verMask | horMask );
+ else
+ sbDirty = sbDirty | (horMask | verMask);
+ if ( testTableFlags( Tbl_hScrollBar ) )
+ coverCornerSquare( TRUE );
+ if ( autoUpdate() )
+ sbDirty = sbDirty | verMask;
+ } else {
+ tFlags &= ~Tbl_vScrollBar;
+ if ( !vScrollBar )
+ return;
+ coverCornerSquare( FALSE );
+ bool hideScrollBar = autoUpdate() && vScrollBar->isVisible();
+ if ( hideScrollBar )
+ vScrollBar->hide();
+ if ( update )
+ updateScrollBars( horMask );
+ else
+ sbDirty = sbDirty | horMask;
+ if ( hideScrollBar && isVisible() )
+ repaint( vScrollBar->x(), vScrollBar->y(),
+ vScrollBar->width(), height() - vScrollBar->y() );
+ }
+ if ( update )
+ updateFrameSize();
+}
+
+
+
+
+int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY,
+ bool goOutsideView ) const
+{
+ int r = -1;
+ if ( nRows == 0 )
+ return r;
+ if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) {
+ if ( yPos < minViewY() ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QtTableView::findRawRow: (%s) internal error: "
+ "yPos < minViewY() && goOutsideView "
+ "not supported. (%d,%d)",
+ name( "unnamed" ), yPos, yOffs );
+#endif
+ return -1;
+ }
+ if ( cellH ) { // uniform cell height
+ r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top
+ if ( cellMaxY )
+ *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1;
+ if ( cellMinY )
+ *cellMinY = r*cellH + minViewY() - yCellDelta;
+ r += yCellOffs; // absolute cell index
+ } else { // variable cell height
+ QtTableView *tw = (QtTableView *)this;
+ r = yCellOffs;
+ int h = minViewY() - yCellDelta; //##arnt3
+ int oldH = h;
+ Q_ASSERT( r < nRows );
+ while ( r < nRows ) {
+ oldH = h;
+ h += tw->cellHeight( r ); // Start of next cell
+ if ( yPos < h )
+ break;
+ r++;
+ }
+ if ( cellMaxY )
+ *cellMaxY = h - 1;
+ if ( cellMinY )
+ *cellMinY = oldH;
+ }
+ }
+ return r;
+
+}
+
+
+int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX ,
+ bool goOutsideView ) const
+{
+ int c = -1;
+ if ( nCols == 0 )
+ return c;
+ if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) {
+ if ( xPos < minViewX() ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QtTableView::findRawCol: (%s) internal error: "
+ "xPos < minViewX() && goOutsideView "
+ "not supported. (%d,%d)",
+ name( "unnamed" ), xPos, xOffs );
+#endif
+ return -1;
+ }
+ if ( cellW ) { // uniform cell width
+ c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left
+ if ( cellMaxX )
+ *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1;
+ if ( cellMinX )
+ *cellMinX = c*cellW + minViewX() - xCellDelta;
+ c += xCellOffs; // absolute cell index
+ } else { // variable cell width
+ QtTableView *tw = (QtTableView *)this;
+ c = xCellOffs;
+ int w = minViewX() - xCellDelta; //##arnt3
+ int oldW = w;
+ Q_ASSERT( c < nCols );
+ while ( c < nCols ) {
+ oldW = w;
+ w += tw->cellWidth( c ); // Start of next cell
+ if ( xPos < w )
+ break;
+ c++;
+ }
+ if ( cellMaxX )
+ *cellMaxX = w - 1;
+ if ( cellMinX )
+ *cellMinX = oldW;
+ }
+ }
+ return c;
+}
+
+
+/*!
+ Returns the index of the row at position \a yPos, where \a yPos is in
+ \e widget coordinates. Returns -1 if \a yPos is outside the valid
+ range.
+
+ \sa findCol(), rowYPos()
+*/
+
+int QtTableView::findRow( int yPos ) const
+{
+ int cellMaxY;
+ int row = findRawRow( yPos, &cellMaxY );
+ if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() )
+ row = - 1; // cell cut by bottom margin
+ if ( row >= nRows )
+ row = -1;
+ return row;
+}
+
+
+/*!
+ Returns the index of the column at position \a xPos, where \a xPos is
+ in \e widget coordinates. Returns -1 if \a xPos is outside the valid
+ range.
+
+ \sa findRow(), colXPos()
+*/
+
+int QtTableView::findCol( int xPos ) const
+{
+ int cellMaxX;
+ int col = findRawCol( xPos, &cellMaxX );
+ if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() )
+ col = - 1; // cell cut by right margin
+ if ( col >= nCols )
+ col = -1;
+ return col;
+}
+
+
+/*!
+ Computes the position in the widget of row \a row.
+
+ Returns TRUE and stores the result in \a *yPos (in \e widget
+ coordinates) if the row is visible. Returns FALSE and does not modify
+ \a *yPos if \a row is invisible or invalid.
+
+ \sa colXPos(), findRow()
+*/
+
+bool QtTableView::rowYPos( int row, int *yPos ) const
+{
+ int y;
+ if ( row >= yCellOffs ) {
+ if ( cellH ) {
+ int lastVisible = lastRowVisible();
+ if ( row > lastVisible || lastVisible == -1 )
+ return FALSE;
+ y = (row - yCellOffs)*cellH + minViewY() - yCellDelta;
+ } else {
+ //##arnt3
+ y = minViewY() - yCellDelta; // y of leftmost cell in view
+ int r = yCellOffs;
+ QtTableView *tw = (QtTableView *)this;
+ int maxY = maxViewY();
+ while ( r < row && y <= maxY )
+ y += tw->cellHeight( r++ );
+ if ( y > maxY )
+ return FALSE;
+
+ }
+ } else {
+ return FALSE;
+ }
+ if ( yPos )
+ *yPos = y;
+ return TRUE;
+}
+
+
+/*!
+ Computes the position in the widget of column \a col.
+
+ Returns TRUE and stores the result in \a *xPos (in \e widget
+ coordinates) if the column is visible. Returns FALSE and does not
+ modify \a *xPos if \a col is invisible or invalid.
+
+ \sa rowYPos(), findCol()
+*/
+
+bool QtTableView::colXPos( int col, int *xPos ) const
+{
+ int x;
+ if ( col >= xCellOffs ) {
+ if ( cellW ) {
+ int lastVisible = lastColVisible();
+ if ( col > lastVisible || lastVisible == -1 )
+ return FALSE;
+ x = (col - xCellOffs)*cellW + minViewX() - xCellDelta;
+ } else {
+ //##arnt3
+ x = minViewX() - xCellDelta; // x of uppermost cell in view
+ int c = xCellOffs;
+ QtTableView *tw = (QtTableView *)this;
+ int maxX = maxViewX();
+ while ( c < col && x <= maxX )
+ x += tw->cellWidth( c++ );
+ if ( x > maxX )
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ if ( xPos )
+ *xPos = x;
+ return TRUE;
+}
+
+
+/*!
+ Moves the visible area of the table right by \a xPixels and
+ down by \a yPixels pixels. Both may be negative.
+
+ \warning You might find that QScrollView offers a higher-level of
+ functionality than using QtTableView and this function.
+
+ This function is \e not the same as QWidget::scroll(); in particular,
+ the signs of \a xPixels and \a yPixels have the reverse semantics.
+
+ \sa setXOffset(), setYOffset(), setOffset(), setTopCell(),
+ setLeftCell()
+*/
+
+void QtTableView::scroll( int xPixels, int yPixels )
+{
+ QWidget::scroll( -xPixels, -yPixels, contentsRect() );
+}
+
+
+/*!
+ Returns the leftmost pixel of the table view in \e view
+ coordinates. This excludes the frame and any header.
+
+ \sa maxViewY(), viewWidth(), contentsRect()
+*/
+
+int QtTableView::minViewX() const
+{
+ return frameWidth();
+}
+
+
+/*!
+ Returns the top pixel of the table view in \e view
+ coordinates. This excludes the frame and any header.
+
+ \sa maxViewX(), viewHeight(), contentsRect()
+*/
+
+int QtTableView::minViewY() const
+{
+ return frameWidth();
+}
+
+
+/*!
+ Returns the rightmost pixel of the table view in \e view
+ coordinates. This excludes the frame and any scroll bar, but
+ includes blank pixels to the right of the visible table data.
+
+ \sa maxViewY(), viewWidth(), contentsRect()
+*/
+
+int QtTableView::maxViewX() const
+{
+ return width() - 1 - frameWidth()
+ - (tFlags & Tbl_vScrollBar ? VSBEXT
+ : 0);
+}
+
+
+/*!
+ Returns the bottom pixel of the table view in \e view
+ coordinates. This excludes the frame and any scroll bar, but
+ includes blank pixels below the visible table data.
+
+ \sa maxViewX(), viewHeight(), contentsRect()
+*/
+
+int QtTableView::maxViewY() const
+{
+ return height() - 1 - frameWidth()
+ - (tFlags & Tbl_hScrollBar ? HSBEXT
+ : 0);
+}
+
+
+/*!
+ Returns the width of the table view, as such, in \e view
+ coordinates. This does not include any header, scroll bar or frame,
+ but it does include background pixels to the right of the table data.
+
+ \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect()
+*/
+
+int QtTableView::viewWidth() const
+{
+ return maxViewX() - minViewX() + 1;
+}
+
+
+/*!
+ Returns the height of the table view, as such, in \e view
+ coordinates. This does not include any header, scroll bar or frame,
+ but it does include background pixels below the table data.
+
+ \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect()
+*/
+
+int QtTableView::viewHeight() const
+{
+ return maxViewY() - minViewY() + 1;
+}
+
+
+void QtTableView::doAutoScrollBars()
+{
+ int viewW = width() - frameWidth() - minViewX();
+ int viewH = height() - frameWidth() - minViewY();
+ bool vScrollOn = testTableFlags(Tbl_vScrollBar);
+ bool hScrollOn = testTableFlags(Tbl_hScrollBar);
+ int w = 0;
+ int h = 0;
+ int i;
+
+ if ( testTableFlags(Tbl_autoHScrollBar) ) {
+ if ( cellW ) {
+ w = cellW*nCols;
+ } else {
+ i = 0;
+ while ( i < nCols && w <= viewW )
+ w += cellWidth( i++ );
+ }
+ if ( w > viewW )
+ hScrollOn = TRUE;
+ else
+ hScrollOn = FALSE;
+ }
+
+ if ( testTableFlags(Tbl_autoVScrollBar) ) {
+ if ( cellH ) {
+ h = cellH*nRows;
+ } else {
+ i = 0;
+ while ( i < nRows && h <= viewH )
+ h += cellHeight( i++ );
+ }
+
+ if ( h > viewH )
+ vScrollOn = TRUE;
+ else
+ vScrollOn = FALSE;
+ }
+
+ if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn )
+ if ( w > viewW - VSBEXT )
+ hScrollOn = TRUE;
+
+ if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn )
+ if ( h > viewH - HSBEXT )
+ vScrollOn = TRUE;
+
+ setHorScrollBar( hScrollOn, FALSE );
+ setVerScrollBar( vScrollOn, FALSE );
+ updateFrameSize();
+}
+
+
+/*!
+ \fn void QtTableView::updateScrollBars()
+
+ Updates the scroll bars' contents and presence to match the table's
+ state. Generally, you should not need to call this.
+
+ \sa setTableFlags()
+*/
+
+/*!
+ Updates the scroll bars' contents and presence to match the table's
+ state \c or \a f.
+
+ \sa setTableFlags()
+*/
+
+void QtTableView::updateScrollBars( uint f )
+{
+ sbDirty = sbDirty | f;
+ if ( inSbUpdate )
+ return;
+ inSbUpdate = TRUE;
+
+ if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) ||
+ testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) )
+ // if range change and auto
+ doAutoScrollBars(); // turn scroll bars on/off if needed
+
+ if ( !autoUpdate() ) {
+ inSbUpdate = FALSE;
+ return;
+ }
+ if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) &&
+ !testTableFlags( Tbl_vScrollBar ) ) {
+ setYOffset( 0 );
+ }
+ if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) &&
+ !testTableFlags( Tbl_hScrollBar ) ) {
+ setXOffset( 0 );
+ }
+ if ( !isVisible() ) {
+ inSbUpdate = FALSE;
+ return;
+ }
+
+ if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) {
+ if ( sbDirty & horGeometry )
+ hScrollBar->setGeometry( 0,height() - HSBEXT,
+ viewWidth() + frameWidth()*2,
+ HSBEXT);
+
+ if ( sbDirty & horSteps ) {
+ if ( cellW )
+ hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() );
+ else
+ hScrollBar->setSteps( 16, viewWidth() );
+ }
+
+ if ( sbDirty & horRange )
+ hScrollBar->setRange( 0, maxXOffset() );
+
+ if ( sbDirty & horValue )
+ hScrollBar->setValue( xOffs );
+
+ // show scrollbar only when it has a sane geometry
+ if ( !hScrollBar->isVisible() )
+ hScrollBar->show();
+ }
+
+ if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) {
+ if ( sbDirty & verGeometry )
+ vScrollBar->setGeometry( width() - VSBEXT, 0,
+ VSBEXT,
+ viewHeight() + frameWidth()*2 );
+
+ if ( sbDirty & verSteps ) {
+ if ( cellH )
+ vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() );
+ else
+ vScrollBar->setSteps( 16, viewHeight() ); // fttb! ###
+ }
+
+ if ( sbDirty & verRange )
+ vScrollBar->setRange( 0, maxYOffset() );
+
+ if ( sbDirty & verValue )
+ vScrollBar->setValue( yOffs );
+
+ // show scrollbar only when it has a sane geometry
+ if ( !vScrollBar->isVisible() )
+ vScrollBar->show();
+ }
+ if ( coveringCornerSquare &&
+ ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) )
+ cornerSquare->move( maxViewX() + frameWidth() + 1,
+ maxViewY() + frameWidth() + 1 );
+
+ sbDirty = 0;
+ inSbUpdate = FALSE;
+}
+
+
+void QtTableView::updateFrameSize()
+{
+ int rw = width() - ( testTableFlags(Tbl_vScrollBar) ?
+ VSBEXT : 0 );
+ int rh = height() - ( testTableFlags(Tbl_hScrollBar) ?
+ HSBEXT : 0 );
+ if ( rw < 0 )
+ rw = 0;
+ if ( rh < 0 )
+ rh = 0;
+
+ if ( autoUpdate() ) {
+ int fh = frameRect().height();
+ int fw = frameRect().width();
+ setFrameRect( QRect(0,0,rw,rh) );
+
+ if ( rw != fw )
+ update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh );
+ if ( rh != fh )
+ update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 );
+ }
+}
+
+
+/*!
+ Returns the maximum horizontal offset within the table of the
+ view's left edge in \e table coordinates.
+
+ This is used mainly to set the horizontal scroll bar's range.
+
+ \sa maxColOffset(), maxYOffset(), totalWidth()
+*/
+
+int QtTableView::maxXOffset()
+{
+ int tw = totalWidth();
+ int maxOffs;
+ if ( testTableFlags(Tbl_scrollLastHCell) ) {
+ if ( nCols != 1)
+ maxOffs = tw - ( cellW ? cellW : cellWidth( nCols - 1 ) );
+ else
+ maxOffs = tw - viewWidth();
+ } else {
+ if ( testTableFlags(Tbl_snapToHGrid) ) {
+ if ( cellW ) {
+ maxOffs = tw - (viewWidth()/cellW)*cellW;
+ } else {
+ int goal = tw - viewWidth();
+ int pos = tw;
+ int nextCol = nCols - 1;
+ int nextCellWidth = cellWidth( nextCol );
+ while( nextCol > 0 && pos > goal + nextCellWidth ) {
+ pos -= nextCellWidth;
+ nextCellWidth = cellWidth( --nextCol );
+ }
+ if ( goal + nextCellWidth == pos )
+ maxOffs = goal;
+ else if ( goal < pos )
+ maxOffs = pos;
+ else
+ maxOffs = 0;
+ }
+ } else {
+ maxOffs = tw - viewWidth();
+ }
+ }
+ return maxOffs > 0 ? maxOffs : 0;
+}
+
+
+/*!
+ Returns the maximum vertical offset within the table of the
+ view's top edge in \e table coordinates.
+
+ This is used mainly to set the vertical scroll bar's range.
+
+ \sa maxRowOffset(), maxXOffset(), totalHeight()
+*/
+
+int QtTableView::maxYOffset()
+{
+ int th = totalHeight();
+ int maxOffs;
+ if ( testTableFlags(Tbl_scrollLastVCell) ) {
+ if ( nRows != 1)
+ maxOffs = th - ( cellH ? cellH : cellHeight( nRows - 1 ) );
+ else
+ maxOffs = th - viewHeight();
+ } else {
+ if ( testTableFlags(Tbl_snapToVGrid) ) {
+ if ( cellH ) {
+ maxOffs = th - (viewHeight()/cellH)*cellH;
+ } else {
+ int goal = th - viewHeight();
+ int pos = th;
+ int nextRow = nRows - 1;
+ int nextCellHeight = cellHeight( nextRow );
+ while( nextRow > 0 && pos > goal + nextCellHeight ) {
+ pos -= nextCellHeight;
+ nextCellHeight = cellHeight( --nextRow );
+ }
+ if ( goal + nextCellHeight == pos )
+ maxOffs = goal;
+ else if ( goal < pos )
+ maxOffs = pos;
+ else
+ maxOffs = 0;
+ }
+ } else {
+ maxOffs = th - viewHeight();
+ }
+ }
+ return maxOffs > 0 ? maxOffs : 0;
+}
+
+
+/*!
+ Returns the index of the last column, which may be at the left edge
+ of the view.
+
+ Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag,
+ this may or may not be the last column.
+
+ \sa maxXOffset(), maxRowOffset()
+*/
+
+int QtTableView::maxColOffset()
+{
+ int mx = maxXOffset();
+ if ( cellW )
+ return mx/cellW;
+ else {
+ int xcd=0, col=0;
+ while ( col < nCols && mx > (xcd=cellWidth(col)) ) {
+ mx -= xcd;
+ col++;
+ }
+ return col;
+ }
+}
+
+
+/*!
+ Returns the index of the last row, which may be at the top edge of
+ the view.
+
+ Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag,
+ this may or may not be the last row.
+
+ \sa maxYOffset(), maxColOffset()
+*/
+
+int QtTableView::maxRowOffset()
+{
+ int my = maxYOffset();
+ if ( cellH )
+ return my/cellH;
+ else {
+ int ycd=0, row=0;
+ while ( row < nRows && my > (ycd=cellHeight(row)) ) {
+ my -= ycd;
+ row++;
+ }
+ return row;
+ }
+}
+
+
+void QtTableView::showOrHideScrollBars()
+{
+ if ( !autoUpdate() )
+ return;
+ if ( vScrollBar ) {
+ if ( testTableFlags(Tbl_vScrollBar) ) {
+ if ( !vScrollBar->isVisible() )
+ sbDirty = sbDirty | verMask;
+ } else {
+ if ( vScrollBar->isVisible() )
+ vScrollBar->hide();
+ }
+ }
+ if ( hScrollBar ) {
+ if ( testTableFlags(Tbl_hScrollBar) ) {
+ if ( !hScrollBar->isVisible() )
+ sbDirty = sbDirty | horMask;
+ } else {
+ if ( hScrollBar->isVisible() )
+ hScrollBar->hide();
+ }
+ }
+ if ( cornerSquare ) {
+ if ( testTableFlags(Tbl_hScrollBar) &&
+ testTableFlags(Tbl_vScrollBar) ) {
+ if ( !cornerSquare->isVisible() )
+ cornerSquare->show();
+ } else {
+ if ( cornerSquare->isVisible() )
+ cornerSquare->hide();
+ }
+ }
+}
+
+
+/*!
+ Updates the scroll bars and internal state.
+
+ Call this function when the table view's total size is changed;
+ typically because the result of cellHeight() or cellWidth() have changed.
+
+ This function does not repaint the widget.
+*/
+
+void QtTableView::updateTableSize()
+{
+ bool updateOn = autoUpdate();
+ setAutoUpdate( FALSE );
+ int xofs = xOffset();
+ xOffs++; //so that setOffset will not return immediately
+ setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly
+ setAutoUpdate(updateOn);
+
+ updateScrollBars( horSteps | horRange |
+ verSteps | verRange );
+ showOrHideScrollBars();
+}
+
+
+#endif
diff --git a/arts/builder/qttableview.h b/arts/builder/qttableview.h
new file mode 100644
index 00000000..c5a540dd
--- /dev/null
+++ b/arts/builder/qttableview.h
@@ -0,0 +1,251 @@
+/**********************************************************************
+** $Id$
+**
+** Definition of QtTableView class
+**
+** Created : 941115
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file contains a class moved out of the Qt GUI Toolkit API. It
+** may be used, distributed and modified without limitation.
+**
+**********************************************************************/
+
+#ifndef QTTABLEVIEW_H
+#define QTTABLEVIEW_H
+
+#ifndef QT_H
+#include "qframe.h"
+#endif // QT_H
+
+#ifndef QT_NO_QTTABLEVIEW
+
+class QScrollBar;
+class QCornerSquare;
+
+
+class QtTableView : public QFrame
+{
+ Q_OBJECT
+public:
+ virtual void setBackgroundColor( const QColor & );
+ virtual void setPalette( const QPalette & );
+ void show();
+
+ void repaint( bool erase=TRUE );
+ void repaint( int x, int y, int w, int h, bool erase=TRUE );
+ void repaint( const QRect &, bool erase=TRUE );
+
+protected:
+ QtTableView( QWidget *parent=0, const char *name=0, WFlags f=0 );
+ ~QtTableView();
+
+ int numRows() const;
+ virtual void setNumRows( int );
+ int numCols() const;
+ virtual void setNumCols( int );
+
+ int topCell() const;
+ virtual void setTopCell( int row );
+ int leftCell() const;
+ virtual void setLeftCell( int col );
+ virtual void setTopLeftCell( int row, int col );
+
+ int xOffset() const;
+ virtual void setXOffset( int );
+ int yOffset() const;
+ virtual void setYOffset( int );
+ virtual void setOffset( int x, int y, bool updateScrBars = TRUE );
+
+ virtual int cellWidth( int col );
+ virtual int cellHeight( int row );
+ int cellWidth() const;
+ int cellHeight() const;
+ virtual void setCellWidth( int );
+ virtual void setCellHeight( int );
+
+ virtual int totalWidth();
+ virtual int totalHeight();
+
+ uint tableFlags() const;
+ bool testTableFlags( uint f ) const;
+ virtual void setTableFlags( uint f );
+ void clearTableFlags( uint f = ~0 );
+
+ bool autoUpdate() const;
+ virtual void setAutoUpdate( bool );
+
+ void updateCell( int row, int column, bool erase=TRUE );
+
+ QRect cellUpdateRect() const;
+ QRect viewRect() const;
+
+ int lastRowVisible() const;
+ int lastColVisible() const;
+
+ bool rowIsVisible( int row ) const;
+ bool colIsVisible( int col ) const;
+
+ QScrollBar *verticalScrollBar() const;
+ QScrollBar *horizontalScrollBar() const;
+
+private slots:
+ void horSbValue( int );
+ void horSbSliding( int );
+ void horSbSlidingDone();
+ void verSbValue( int );
+ void verSbSliding( int );
+ void verSbSlidingDone();
+
+protected:
+ virtual void paintCell( QPainter *, int row, int col ) = 0;
+ virtual void setupPainter( QPainter * );
+
+ void paintEvent( QPaintEvent * );
+ void resizeEvent( QResizeEvent * );
+
+ int findRow( int yPos ) const;
+ int findCol( int xPos ) const;
+
+ bool rowYPos( int row, int *yPos ) const;
+ bool colXPos( int col, int *xPos ) const;
+
+ int maxXOffset();
+ int maxYOffset();
+ int maxColOffset();
+ int maxRowOffset();
+
+ int minViewX() const;
+ int minViewY() const;
+ int maxViewX() const;
+ int maxViewY() const;
+ int viewWidth() const;
+ int viewHeight() const;
+
+ void scroll( int xPixels, int yPixels );
+ void updateScrollBars();
+ void updateTableSize();
+
+private:
+ void coverCornerSquare( bool );
+ void snapToGrid( bool horizontal, bool vertical );
+ virtual void setHorScrollBar( bool on, bool update = TRUE );
+ virtual void setVerScrollBar( bool on, bool update = TRUE );
+ void updateView();
+ int findRawRow( int yPos, int *cellMaxY, int *cellMinY = 0,
+ bool goOutsideView = FALSE ) const;
+ int findRawCol( int xPos, int *cellMaxX, int *cellMinX = 0,
+ bool goOutsideView = FALSE ) const;
+ int maxColsVisible() const;
+
+ void updateScrollBars( uint );
+ void updateFrameSize();
+
+ void doAutoScrollBars();
+ void showOrHideScrollBars();
+
+ int nRows;
+ int nCols;
+ int xOffs, yOffs;
+ int xCellOffs, yCellOffs;
+ short xCellDelta, yCellDelta;
+ short cellH, cellW;
+
+ uint eraseInPaint : 1;
+ uint verSliding : 1;
+ uint verSnappingOff : 1;
+ uint horSliding : 1;
+ uint horSnappingOff : 1;
+ uint coveringCornerSquare : 1;
+ uint sbDirty : 8;
+ uint inSbUpdate : 1;
+
+ uint tFlags;
+ QRect cellUpdateR;
+
+ QScrollBar *vScrollBar;
+ QScrollBar *hScrollBar;
+ QCornerSquare *cornerSquare;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QtTableView( const QtTableView & );
+ QtTableView &operator=( const QtTableView & );
+#endif
+};
+
+
+const uint Tbl_vScrollBar = 0x00000001;
+const uint Tbl_hScrollBar = 0x00000002;
+const uint Tbl_autoVScrollBar = 0x00000004;
+const uint Tbl_autoHScrollBar = 0x00000008;
+const uint Tbl_autoScrollBars = 0x0000000C;
+
+const uint Tbl_clipCellPainting = 0x00000100;
+const uint Tbl_cutCellsV = 0x00000200;
+const uint Tbl_cutCellsH = 0x00000400;
+const uint Tbl_cutCells = 0x00000600;
+
+const uint Tbl_scrollLastHCell = 0x00000800;
+const uint Tbl_scrollLastVCell = 0x00001000;
+const uint Tbl_scrollLastCell = 0x00001800;
+
+const uint Tbl_smoothHScrolling = 0x00002000;
+const uint Tbl_smoothVScrolling = 0x00004000;
+const uint Tbl_smoothScrolling = 0x00006000;
+
+const uint Tbl_snapToHGrid = 0x00008000;
+const uint Tbl_snapToVGrid = 0x00010000;
+const uint Tbl_snapToGrid = 0x00018000;
+
+
+inline int QtTableView::numRows() const
+{ return nRows; }
+
+inline int QtTableView::numCols() const
+{ return nCols; }
+
+inline int QtTableView::topCell() const
+{ return yCellOffs; }
+
+inline int QtTableView::leftCell() const
+{ return xCellOffs; }
+
+inline int QtTableView::xOffset() const
+{ return xOffs; }
+
+inline int QtTableView::yOffset() const
+{ return yOffs; }
+
+inline int QtTableView::cellHeight() const
+{ return cellH; }
+
+inline int QtTableView::cellWidth() const
+{ return cellW; }
+
+inline uint QtTableView::tableFlags() const
+{ return tFlags; }
+
+inline bool QtTableView::testTableFlags( uint f ) const
+{ return (tFlags & f) != 0; }
+
+inline QRect QtTableView::cellUpdateRect() const
+{ return cellUpdateR; }
+
+inline bool QtTableView::autoUpdate() const
+{ return isUpdatesEnabled(); }
+
+inline void QtTableView::repaint( bool erase )
+{ repaint( 0, 0, width(), height(), erase ); }
+
+inline void QtTableView::repaint( const QRect &r, bool erase )
+{ repaint( r.x(), r.y(), r.width(), r.height(), erase ); }
+
+inline void QtTableView::updateScrollBars()
+{ updateScrollBars( 0 ); }
+
+
+#endif // QT_NO_QTTABLEVIEW
+
+#endif // QTTABLEVIEW_H
diff --git a/arts/builder/retrievedlg.cpp b/arts/builder/retrievedlg.cpp
new file mode 100644
index 00000000..59a8079f
--- /dev/null
+++ b/arts/builder/retrievedlg.cpp
@@ -0,0 +1,137 @@
+ /*
+
+ Copyright (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 "retrievedlg.h"
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlistbox.h>
+#include <kbuttonbox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qlineedit.h>
+#include <kapplication.h>
+#include <kseparator.h>
+#include <klocale.h>
+#include <kstdguiitem.h>
+#include <stdio.h>
+#include <set>
+#include <arts/debug.h>
+#include <qpushbutton.h>
+
+static void min_size(QWidget *w) {
+ w->setMinimumSize(w->sizeHint());
+}
+
+RetrieveDlg::RetrieveDlg(QWidget *parent) :QDialog(parent,"X", TRUE)
+{
+ setCaption(i18n("Retrieve Structure From Server"));
+
+ QVBoxLayout *mainlayout = new QVBoxLayout(this);
+
+// caption label: "Synthesis running..."
+
+ mainlayout->addSpacing(5);
+ QLabel *captionlabel = new QLabel(this);
+ QFont labelfont(captionlabel->font());
+ labelfont.setPointSize(labelfont.pointSize()*3/2);
+ captionlabel->setFont(labelfont);
+ captionlabel->setText(QString(" ")+i18n("Published structures")+QString(" "));
+ captionlabel->setAlignment(AlignCenter);
+ min_size(captionlabel);
+ mainlayout->addWidget(captionlabel);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler2 = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler2);
+ mainlayout->addSpacing(5);
+
+// listwidget
+
+ listbox = new QListBox(this);
+ listbox->setMinimumSize(300,200);
+
+ arts_debug("TODO:PORT:get available structures");
+#if 0
+ // sort the result:
+ vector<StructureDesc> *structures = Synthesizer->publishedStructures();
+ set<string> names;
+
+ unsigned long i;
+ for(i=0;i<structures->length();i++)
+ names.insert(structures[i]->Name());
+
+ set<string>::iterator ni;
+ for(ni=names.begin();ni!=names.end();++ni)
+ listbox->insertItem((*ni).c_str());
+#endif
+
+ mainlayout->addWidget(listbox);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler);
+ mainlayout->addSpacing(5);
+
+// buttons
+
+ QHBoxLayout *buttonlayout = new QHBoxLayout;
+ mainlayout->addSpacing(5);
+ mainlayout->addLayout(buttonlayout);
+ mainlayout->addSpacing(5);
+
+ buttonlayout->addSpacing(5);
+ KButtonBox *bbox = new KButtonBox(this);
+
+ bbox->addButton(KStdGuiItem::help(), this, SLOT( help() ));
+ bbox->addStretch(1);
+
+ QButton *cancelbutton = bbox->addButton(KStdGuiItem::cancel());
+ connect( cancelbutton, SIGNAL( clicked() ), SLOT(reject() ) );
+
+ QButton *okbutton = bbox->addButton(KStdGuiItem::ok());
+ connect( okbutton, SIGNAL( clicked() ), SLOT(accept() ) );
+
+ bbox->layout();
+
+ buttonlayout->addWidget(bbox);
+ buttonlayout->addSpacing(5);
+
+ mainlayout->freeze();
+}
+
+QString RetrieveDlg::result()
+{
+ if(listbox->currentItem() != -1)
+ {
+ return(listbox->text(listbox->currentItem()));
+ }
+ return QString::null;
+}
+
+void RetrieveDlg::help()
+{
+ KApplication::kApplication()->invokeHelp("", "karts");
+}
+#include "retrievedlg.moc"
diff --git a/arts/builder/retrievedlg.h b/arts/builder/retrievedlg.h
new file mode 100644
index 00000000..e37d3120
--- /dev/null
+++ b/arts/builder/retrievedlg.h
@@ -0,0 +1,45 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef __RETRIEVEDLG_H_
+#define __RETRIEVEDLG_H_
+
+#include "structure.h"
+
+#include <qdialog.h>
+#include <qtimer.h>
+#include <qlabel.h>
+#include <qscrollbar.h>
+#include <qlineedit.h>
+#include <qlayout.h>
+#include <qlistbox.h>
+#include <string>
+
+class RetrieveDlg :public QDialog {
+ Q_OBJECT
+ QListBox *listbox;
+public:
+ RetrieveDlg(QWidget *parent);
+ QString result();
+public slots:
+ void help();
+};
+#endif
diff --git a/arts/builder/scomponent.cpp b/arts/builder/scomponent.cpp
new file mode 100644
index 00000000..e894abaa
--- /dev/null
+++ b/arts/builder/scomponent.cpp
@@ -0,0 +1,108 @@
+ /*
+
+ Copyright (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 "scomponent.h"
+//#include <arts/debug.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <stdio.h>
+
+StructureComponent::StructureComponent(StructureCanvas *canvas)
+: _x(0), _y(0)
+{
+ this->canvas = canvas;
+}
+
+StructureComponent::~StructureComponent()
+{
+}
+
+void StructureComponent::hide()
+{
+ if(_visible)
+ {
+ _visible = false;
+ redraw();
+ }
+}
+
+void StructureComponent::show()
+{
+ if(!_visible)
+ {
+ _visible = true;
+ redraw();
+ }
+}
+
+bool StructureComponent::visible()
+{
+ return(_visible);
+}
+
+void StructureComponent::redraw()
+{
+ canvas->redrawRect(x(), y(), width(), height());
+}
+
+bool StructureComponent::move(int newx, int newy)
+{
+ bool success = moveInternal(newx, newy);
+
+ if(success)
+ {
+ hide();
+ redraw();
+
+ _x = newx;
+ _y = newy;
+
+ show();
+ redraw();
+ }
+
+ return success;
+}
+
+int StructureComponent::x() const
+{
+ return _x;
+}
+
+int StructureComponent::y() const
+{
+ return _y;
+}
+
+bool StructureComponent::selected()
+{
+ return _selected;
+}
+
+void StructureComponent::setSelected(bool newselection)
+{
+ if(newselection != _selected)
+ {
+ _selected = newselection;
+ redraw();
+ }
+}
+
diff --git a/arts/builder/scomponent.h b/arts/builder/scomponent.h
new file mode 100644
index 00000000..c5bdcbad
--- /dev/null
+++ b/arts/builder/scomponent.h
@@ -0,0 +1,87 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef __SCOMPONENT_H__
+#define __SCOMPONENT_H__
+
+#include <qstring.h>
+#include <list>
+
+class ModulePort;
+class QPainter;
+class QPixmap;
+
+class StructureCanvas {
+public:
+ virtual void redrawRect(int x, int y, int width, int height) = 0;
+};
+
+class StructureComponent {
+protected:
+ StructureCanvas *canvas;
+
+ int _x, _y;
+ bool _selected, _visible;
+
+ virtual bool moveInternal(int x, int y) = 0;
+
+public:
+ StructureComponent(StructureCanvas *canvas);
+ virtual ~StructureComponent();
+
+ // type
+
+ enum ComponentType { ctModule, ctPort };
+ virtual ComponentType type() = 0;
+
+ // TODO: connection & autorouter
+
+ virtual ModulePort *portAt(int segment, int x, int y) = 0;
+ virtual void dumpPorts(std::list<ModulePort *>& ports) = 0;
+
+ // visibility
+ bool visible();
+ void show();
+ void hide();
+ void redraw();
+
+ // drawing
+ virtual bool drawNeedsBackground(int segment) = 0;
+ virtual void drawSegment(QPainter *dest, int cellsize, int segment) = 0;
+ virtual QPixmap *pixmap() = 0;
+ virtual QString name() = 0;
+
+ // space checking & positioning (dimensions in cells)
+ bool move(int x, int y);
+ int x() const;
+ int y() const;
+ virtual int width() const = 0;
+ virtual int height() const = 0;
+
+ // selection
+ bool selected();
+ void setSelected(bool newselection);
+
+ // creation and destruction are handled via standard
+ // constructors/destructors
+};
+
+#endif
diff --git a/arts/builder/session.cpp b/arts/builder/session.cpp
new file mode 100644
index 00000000..46efd7e1
--- /dev/null
+++ b/arts/builder/session.cpp
@@ -0,0 +1,80 @@
+ /*
+
+ Copyright (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 "session.h"
+#include <stdio.h>
+#include <arts/debug.h>
+
+Session::Session()
+{
+ session = 0;
+}
+
+Session::~Session()
+{
+ if(session) delete session;
+ session = 0;
+}
+
+bool Session::startExecute()
+{
+ arts_debug("TODO:PORT: Session::startExecute()");
+#if 0
+ assert(session);
+ assert(!execID);
+
+ // just in case synthesis has been halted before,
+ // restart it and hope we'll have enough computing power now
+ Synthesizer->Reset();
+ execID = Synthesizer->restoreSession(*session,preferredservers);
+#endif
+ return true;
+}
+
+bool Session::loadSession(const char *filename)
+{
+#if 0
+ if(session) delete session;
+ session = 0;
+
+ FILE *infile = fopen(filename,"r");
+ if(!infile) return false;
+
+ session = new ArtsCorba::StringSeq;
+
+ char line[1024];
+ unsigned long i = 0;
+
+ while(fgets(line,1024,infile))
+ {
+ // cut eventual CR and/or LFs at the end of the line
+ while(strlen(line) && line[strlen(line)-1] < 14)
+ line[strlen(line)-1] = 0;
+
+ session->length(i+1);
+ (*session)[i++] = CORBA::string_dup(line);
+ }
+ fclose(infile);
+ return true;
+#endif
+ arts_debug("TODO:PORT:loadSession(%s)",filename);
+ return false;
+}
diff --git a/arts/builder/session.h b/arts/builder/session.h
new file mode 100644
index 00000000..bfa0c3d8
--- /dev/null
+++ b/arts/builder/session.h
@@ -0,0 +1,38 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef __SESSION_H__
+#define __SESSION_H__
+
+#include "structure.h"
+
+class Session :public ExecutableStructure {
+ std::vector<std::string> *session;
+public:
+ Session();
+ ~Session();
+
+ bool startExecute();
+
+ bool loadSession(const char *filename);
+};
+
+#endif
diff --git a/arts/builder/structure.cpp b/arts/builder/structure.cpp
new file mode 100644
index 00000000..37950119
--- /dev/null
+++ b/arts/builder/structure.cpp
@@ -0,0 +1,462 @@
+ /*
+
+ Copyright (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 "structure.h"
+#include "soundserver.h"
+#include "kartsserver.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#include <fstream>
+#include <kdebug.h>
+#include <arts/debug.h>
+
+using namespace std;
+
+ExecutableStructure::ExecutableStructure()
+{
+}
+
+ExecutableStructure::~ExecutableStructure()
+{
+ // to make destructor virtual
+ // stop execution here?
+}
+
+void ExecutableStructure::stopExecute()
+{
+ arts_debug("TODO: PORT: freeStructure");
+}
+
+bool ExecutableStructure::isExecuting()
+{
+ arts_debug("TODO:PORT:isExecuting()");
+ return false;
+}
+
+bool ExecutableStructure::saveSession(const char *filename)
+{
+ arts_debug("TODO:PORT:saveSession()");
+#if 0
+ assert(execID);
+
+ ArtsCorba::StringSeq_var data;
+ arts_debug("saveSession");
+ if(Synthesizer->saveSession(execID,true,data))
+ {
+ arts_debug("ok");
+ FILE *file = fopen(filename,"w");
+ if(!file) return false;
+
+ unsigned long i;
+ for(i=0;i<data->length();i++) fprintf(file,"%s\n",(char *)(*data)[i]);
+ fclose(file);
+
+ return true;
+ }
+ arts_debug("failed");
+#endif
+ return false;
+}
+
+Structure::Structure() :ExecutableStructure()
+{
+ canvas = 0;
+}
+
+void Structure::setCanvas(StructureCanvas *canvas)
+{
+ this->canvas = canvas;
+}
+
+Structure::~Structure()
+{
+ clear();
+ arts_debug("~Structure (releasing structuredesc from structure)");
+}
+
+bool Structure::startExecute()
+{
+#if 0
+ assert(!execID);
+
+ arts_debug("PORT: TODO startExecute()");
+ // just in case synthesis has been halted before,
+ // restart it and hope we'll have enough computing power now
+ //Synthesizer->Reset();
+ //execID = Synthesizer->createStructure(StructureDesc,preferredservers);
+ assert(execID);
+#endif
+
+ /* connect to the sound server */
+ Arts::SimpleSoundServer server = KArtsServer().server();
+
+ if(server.isNull())
+ return false;
+
+ /* move a copy of the structure to the server, so that there will be
+ no latencies in querying what to connect to what */
+ vector<string> *savePtr = StructureDesc.saveToList();
+ Arts::StructureDesc remoteSD;
+ remoteSD = Arts::DynamicCast(server.createObject("Arts::StructureDesc"));
+ assert(!remoteSD.isNull());
+ remoteSD.loadFromList(*savePtr);
+ delete savePtr;
+
+ /* create a structure builder on the server */
+ Arts::StructureBuilder builder;
+ builder = Arts::DynamicCast(server.createObject("Arts::StructureBuilder"));
+
+ /* create a local factory - this will enable the builder to create gui qt
+ widgets (which need to reside within an qt application to work) */
+
+ Arts::LocalFactory factory;
+ builder.addFactory(factory);
+
+ /* create the structure on the server */
+ structure = Arts::DynamicCast(builder.createObject(remoteSD));
+
+ if (structure.isNull())
+ return false;
+
+ structure.start();
+
+ return true;
+}
+
+void Structure::stopExecute()
+{
+
+ // TODO:PORT: verify this code
+ structure = Arts::SynthModule::null();
+}
+
+void Structure::publish()
+{
+ arts_debug("PORT: TODO publish()");
+ //Synthesizer->publishStructureDesc(StructureDesc);
+}
+
+bool Structure::valid()
+{
+ return StructureDesc.valid();
+}
+
+string Structure::name()
+{
+ return StructureDesc.name();
+}
+
+void Structure::rename(const char *newname)
+{
+ StructureDesc.name(newname);
+}
+
+void Structure::addInheritedInterface(const char *iface)
+{
+ StructureDesc.addInheritedInterface(iface);
+}
+
+vector<string> *Structure::inheritedInterfaces()
+{
+ return StructureDesc.inheritedInterfaces();
+}
+
+void Structure::removeInheritedInterface(const char *iface)
+{
+ StructureDesc.removeInheritedInterface(iface);
+}
+
+void Structure::saveInto(FILE *file)
+{
+ vector<string> *list = StructureDesc.saveToList();
+
+ vector<string>::iterator i;
+
+ for(i = list->begin(); i != list->end(); i++)
+ fprintf(file, "%s\n", (*i).c_str());
+
+ delete list;
+}
+
+bool Structure::save(const char *filename)
+{
+ FILE *file = fopen(filename,"w");
+ if (!file)
+ return false;
+
+ saveInto(file);
+
+ fclose(file);
+
+ return true;
+}
+
+void Structure::clear()
+{
+ list<StructureComponent *>::iterator ci;
+
+ arts_debug("clc");
+/*
+ for(ci = ComponentList.begin(); ci != ComponentList.end(); ++ci)
+ delete (*ci);
+
+ ComponentList.erase(ComponentList.begin(), ComponentList.end());
+ ModuleList.erase(ModuleList.begin(), ModuleList.end());
+*/
+ for(ci = ComponentList.begin(); ci != ComponentList.end(); ++ci)
+ (*ci)->setSelected(true);
+ deleteSelected();
+
+ arts_debug("sdc");
+ // shouldn't do much, now that we deleted every single component of
+ // the structure, but we to it anyway, just to be sure.
+ StructureDesc.clear();
+}
+
+void Structure::retrieve(const char *pubname)
+{
+ arts_debug("PORT: TODO: retrieve");
+#if 0
+ arts_debug("retrieve... %s",pubname);
+ ArtsCorba::StructureDesc_var psd = Synthesizer->lookupStructureDesc(pubname);
+
+ arts_debug("psdlookup ok");
+ if(psd)
+ {
+ arts_debug("starting savetolist");
+ ArtsCorba::StringSeq_var strseq=psd->saveToList();
+ arts_debug("savetolist ok");
+ loadFromList(strseq);
+ arts_debug("loadfromlist ok");
+ }
+ arts_debug("retrieve... ok");
+#endif
+}
+
+void Structure::load(const char *filename)
+{
+ ifstream infile(filename);
+ string line;
+ vector<string> strseq;
+
+ while(getline(infile,line))
+ strseq.push_back(line);
+
+ loadFromList(strseq);
+#if 0
+ FILE *infile = fopen(filename,"r");
+ ArtsCorba::StringSeq_var strseq = new ArtsCorba::StringSeq;
+
+ char line[1024];
+ unsigned long i = 0;
+
+ while(fgets(line,1024,infile))
+ {
+ // cut eventual CR and/or LFs at the end of the line
+ while(strlen(line) && line[strlen(line)-1] < 14)
+ line[strlen(line)-1] = 0;
+
+ strseq->length(i+1);
+ (*strseq)[i++] = CORBA::string_dup(line);
+ }
+ fclose(infile);
+
+ arts_debug(">>loadfromlist...");
+ loadFromList(strseq);
+ arts_debug("<<loadfromlist...");
+#endif
+}
+
+void Structure::loadFromList(const vector<string>& strseq)
+{
+ assert(canvas);
+
+ arts_debug(">>clear");
+ clear();
+ arts_debug("<<clear");
+
+ StructureDesc.loadFromList(strseq);
+
+ vector<Arts::ModuleDesc> *modules = StructureDesc.modules();
+ vector<Arts::ModuleDesc>::iterator mi;
+
+ for(mi=modules->begin(); mi != modules->end(); ++mi)
+ {
+ Module *m = new Module(*mi,StructureDesc,canvas);
+
+ m->show();
+ ModuleList.push_back(m);
+ ComponentList.push_back(m);
+ }
+ delete modules;
+
+ vector<Arts::StructurePortDesc> *ports = StructureDesc.ports();
+ vector<Arts::StructurePortDesc>::iterator pi;
+
+ for(pi=ports->begin(); pi != ports->end(); ++pi)
+ {
+ StructurePort *p = new StructurePort(*pi,StructureDesc,canvas);
+
+ p->show();
+ ComponentList.push_back(p);
+ }
+ delete ports;
+}
+
+Module *Structure::createModule(const Arts::ModuleInfo& minfo)
+{
+ assert(canvas);
+ Module *m = new Module(minfo,StructureDesc,canvas);
+
+ ComponentList.push_back(m);
+ ModuleList.push_back(m);
+ return m;
+}
+
+StructurePort *Structure::createStructurePort(const Arts::PortType& type)
+{ // TODO:PORT: verify this code
+#if 0
+ arts_debug("TODO:PORT:createStructurePort");
+#endif
+// portname generation
+ unsigned long portindex = 1,l,baselen;;
+ char name[100];
+
+ string namebase;
+ if(type.direction == Arts::input) {
+ // this is a port where our structure puts its results
+ // so it is an input port, that is named out
+ namebase = "out"; baselen = 3;
+ } else {
+ // this is a port where our structure gets data from
+ // so it is an output port, that is named in
+ namebase = "in"; baselen = 2;
+ }
+
+ vector<Arts::StructurePortDesc> *sps = StructureDesc.ports();
+
+ for(l=0;l<sps->size();l++) {
+ string thisname = (*sps)[l].name();
+ if(strncmp(thisname.c_str(), namebase.c_str(), baselen) == 0 &&
+ strlen(thisname.c_str()) > baselen)
+ {
+ unsigned long index2 = atol(&thisname.c_str()[baselen]);
+ if(index2 >= portindex) portindex = index2+1;
+ }
+ }
+ delete sps;
+
+ sprintf(name,"%s%ld",namebase.c_str(),portindex);
+ arts_debug("new Portname: %s",name);
+ Arts::StructurePortDesc spd =
+ StructureDesc.createStructurePortDesc(type,name);
+
+ assert(canvas);
+ StructurePort *s = new StructurePort(spd,StructureDesc,canvas);
+ ComponentList.push_back(s);
+ return s;
+}
+
+list<Module *> *Structure::getModuleList()
+{
+ return(&ModuleList);
+}
+
+list<StructureComponent *> *Structure::getComponentList()
+{
+ return(&ComponentList);
+}
+
+long Structure::countSelected()
+{
+ list<StructureComponent *>::iterator ci;
+ long targets = 0;
+
+ for(ci=ComponentList.begin();ci!=ComponentList.end();++ci)
+ if((*ci)->selected()) targets++;
+
+ return targets;
+}
+
+void Structure::deleteSelected()
+{
+ arts_debug("deleteSelected...");
+
+ // remove module from the ModuleList
+ list<Module *>::iterator mi;
+ for(mi=ModuleList.begin();mi!=ModuleList.end();)
+ {
+ if((*mi)->selected())
+ {
+ mi = ModuleList.erase(mi);
+ }
+ else mi++;
+ }
+
+ // disconnect ports (it might be useful to get this right in the model
+ // instead of doing it in the view - however at it works without end
+ // user visible bugs like this)
+
+ list<StructureComponent *>::iterator ci;
+ list<ModulePort *> allPorts;
+
+ for(ci = ComponentList.begin(); ci!=ComponentList.end(); ++ci)
+ if((*ci)->selected())
+ (*ci)->dumpPorts(allPorts);
+
+ list<ModulePort *>::iterator pi;
+ for(pi = allPorts.begin(); pi != allPorts.end(); ++pi)
+ (*pi)->PortDesc.disconnectAll();
+
+ // and from the ComponentList (the future ;)
+
+ ci = ComponentList.begin();
+ while(ci!=ComponentList.end())
+ {
+ if((*ci)->selected())
+ {
+ delete (*ci);
+ ci = ComponentList.erase(ci);
+ }
+ else ci++;
+ }
+
+ arts_debug("deleteSelected ok.");
+}
+
+StructureComponent *Structure::componentAt(long x, long y, bool ignore_selected)
+{
+ list<StructureComponent *>::iterator ci;
+
+ for(ci=ComponentList.begin();ci!=ComponentList.end();++ci)
+ {
+ StructureComponent *c = *ci;
+
+ if(x >= c->x() && x < c->x()+c->width() &&
+ y >= c->y() && y < c->y()+c->height())
+ {
+ if((c->selected() && !ignore_selected) || !c->selected()) return c;
+ }
+ }
+
+ return 0;
+}
diff --git a/arts/builder/structure.h b/arts/builder/structure.h
new file mode 100644
index 00000000..7717f3ef
--- /dev/null
+++ b/arts/builder/structure.h
@@ -0,0 +1,92 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef __STRUCTURE_H_
+#define __STRUCTURE_H_
+
+#include "artsbuilder.h"
+#include "module.h"
+#include "scomponent.h"
+#include "structureport.h"
+#include "artsflow.h"
+#include <vector>
+
+using namespace std;
+
+class ExecutableStructure
+{
+public:
+ ExecutableStructure();
+ virtual ~ExecutableStructure();
+
+ virtual bool startExecute() = 0;
+ virtual void stopExecute();
+ virtual bool isExecuting();
+ virtual bool saveSession(const char *filename);
+};
+
+class Structure :public ExecutableStructure
+{
+ Arts::StructureDesc StructureDesc;
+ Arts::SynthModule structure;
+ StructureCanvas *canvas;
+
+ std::list<Module *> ModuleList;
+ std::list<StructureComponent *> ComponentList;
+
+public:
+ Structure();
+ ~Structure();
+
+ void setCanvas(StructureCanvas *canvas);
+
+ bool startExecute();
+ void stopExecute();
+
+ bool valid();
+ void load(const char *filename);
+ void retrieve(const char *pubname);
+ void loadFromList(const std::vector<std::string>& strseq);
+ void saveInto(FILE *file);
+ bool save(const char *filename);
+ void clear();
+ void publish();
+
+ long countSelected();
+ void deleteSelected();
+
+ std::string name();
+ void rename(const char *newname);
+
+ void addInheritedInterface(const char *iface);
+ void removeInheritedInterface(const char *iface);
+ vector<std::string> *inheritedInterfaces();
+
+ Module *createModule(const Arts::ModuleInfo& minfo);
+ StructurePort *createStructurePort(const Arts::PortType& type);
+
+ StructureComponent *componentAt(long x, long y, bool ignore_selected);
+
+ std::list<Module *> *getModuleList();
+ std::list<StructureComponent *> *getComponentList();
+};
+
+#endif
diff --git a/arts/builder/structureport.cpp b/arts/builder/structureport.cpp
new file mode 100644
index 00000000..a645d60a
--- /dev/null
+++ b/arts/builder/structureport.cpp
@@ -0,0 +1,287 @@
+ /*
+
+ Copyright (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 "structureport.h"
+#include "drawutils.h"
+#include <qpainter.h>
+#include <qpalette.h>
+#include <qdrawutil.h>
+#include <qbitmap.h>
+#include <assert.h>
+#include <stdio.h>
+#include <arts/debug.h>
+
+using namespace std;
+
+StructurePort::StructurePort(Arts::StructurePortDesc SPortDesc,
+ Arts::StructureDesc StructureDesc, StructureCanvas *canvas)
+ : StructureComponent(canvas)
+{
+ string portname = SPortDesc.name();
+ this->SPortDesc = SPortDesc;
+ this->StructureDesc = StructureDesc;
+ _x = SPortDesc.x();
+ _y = SPortDesc.y();
+ _selected = false;
+ _visible = false;
+
+ ModulePort::Direction dir;
+ if(SPortDesc.type().direction == Arts::input)
+ dir = ModulePort::in;
+ else
+ dir = ModulePort::out;
+
+ if(SPortDesc.type().connType == Arts::conn_property)
+ arts_debug("got property here....");
+ // owner, description, portnr
+ arts_debug(">>creating structureport: %s",portname.c_str());
+ _port = new ModulePort(this, portname.c_str(), 0, dir,this->SPortDesc);
+ arts_debug("<<");
+}
+
+StructurePort::~StructurePort()
+{
+ hide();
+ StructureDesc.freeStructurePortDesc(SPortDesc);
+ delete _port;
+}
+
+bool StructurePort::moveInternal(int x, int y)
+{
+ return SPortDesc.moveTo(x, y);
+}
+
+int StructurePort::width() const
+{
+ return 1;
+}
+
+int StructurePort::height() const
+{
+ return 1;
+}
+
+StructureComponent::ComponentType StructurePort::type()
+{
+ return ctPort;
+}
+
+bool StructurePort::drawNeedsBackground(int segment)
+{
+ assert(segment==0);
+ return true;
+}
+
+void StructurePort::drawSegment(QPainter *dest, int cellsize, int segment)
+{
+ QString pname = QString::fromLocal8Bit(SPortDesc.name().c_str());
+ assert(segment==0);
+
+ QPainter &p = *dest;
+
+ int direction = (_port->direction == ModulePort::out)?1:0;
+
+// FIXME: make these color defs available at one central place, they
+// are currently copied from main.cpp
+
+ QColor mcolor(43,43,168);
+ QColor mcolorlight(164,176,242);
+ QColorGroup g( Qt::white, Qt::blue, mcolorlight, mcolor.dark(), mcolor,
+ Qt::black, Qt::black );
+ QBrush fill( mcolor );
+ QPen textpen(QColor(255,255,180),1);
+ int border = cellsize/10;
+ int boxtop = (cellsize/2)*(1-direction);
+
+ qDrawShadePanel(&p,0,boxtop,cellsize,cellsize/2, g, false, 1, &fill);
+ p.setPen(textpen);
+
+ // Selection box
+ if(_selected)
+ {
+ QPen pen(Qt::white,1,Qt::DotLine);
+
+ p.setPen(pen);
+ p.drawRect(0,boxtop,cellsize,cellsize/2);
+ }
+ // ... doesn't look centered without the 2*border ?!?
+ int textwidth;
+ QString label=DrawUtils::cropText(&p, pname, cellsize-border*2, textwidth);
+ p.drawText(border,border+boxtop,cellsize-border-1,(cellsize/2-1)-2*border,
+ Qt::AlignCenter,label);
+
+ int arrowwidth = cellsize/4;
+
+ int i;
+ for(i=0;i<3;i++)
+ {
+ QBrush fbrush;
+ int delta = 0;
+ switch(i)
+ {
+ case 0: delta = 0;
+ fbrush = QBrush(g.light());
+ break;
+ case 1: delta = 2;
+ fbrush = QBrush(g.dark());
+ break;
+ case 2: delta = 1;
+ fbrush = fill;
+ break;
+ }
+
+/**********************
+- | |
+c | |
+- -+ +-
+d | |
+- \ /
+ \ /
+ \_/
+ |b| w |b|
+*********************/
+
+ int t = (cellsize/2-1)*direction; // top
+ int l = delta; // left
+ int w = arrowwidth-2; // arrow body width
+ int h = cellsize/2; // total arrow height
+
+ int b = (cellsize/2-arrowwidth)/2; // x border width
+/*
+ int c = cellsize/10;
+ int d = cellsize/6;
+*/
+ int c = cellsize/12;
+ int d = cellsize/5;
+
+ QPointArray a(9);
+ a.setPoint(0,b+l,t);
+ a.setPoint(1,b+l,t+c);
+ a.setPoint(2,l,t+c);
+ a.setPoint(3,l,t+c+d);
+ a.setPoint(4,b+w/2+l,t+h);
+ a.setPoint(5,b*2+w+l,t+c+d);
+ a.setPoint(6,b*2+w+l,t+c);
+ a.setPoint(7,b+w+l,t+c);
+ a.setPoint(8,b+w+l,t);
+ //a.setPoint(9,b+l,t);
+/*
+ a.setPoint(0,t,b+l);
+ a.setPoint(1,t+c,b+l);
+ a.setPoint(2,t+c,l);
+ a.setPoint(3,t+c+d,l);
+ a.setPoint(4,t+h,b+w/2+l);
+ a.setPoint(5,t+c+d,b*2+w+l);
+ a.setPoint(6,t+c,b*2+w+l);
+ a.setPoint(7,t+c,b+w+l);
+ a.setPoint(8,t,b+w+l);
+ a.setPoint(9,t,b+l);
+*/
+ p.setPen(Qt::NoPen);
+ p.setBrush(fbrush);
+ p.drawPolygon(a);
+ if(delta==1 && direction==0)
+ {
+ p.setPen(g.light());
+ p.drawLine(b+l,t,b+w+l,t);
+ }
+/*
+ p.fillRect((cellsize/2-arrowwidth)/2+delta,cellsize/2-1,
+ arrowwidth,cellsize/2,fbrush);
+*/
+ }
+ {
+ int border = cellsize/7;
+
+ QBrush pbrush(_port->color(false));
+
+ _port->clickrect = QRect(border,direction * cellsize/2 + border,
+ cellsize/2-2*border, cellsize/2-2*border);
+ qDrawShadePanel(&p, _port->clickrect, g, _port->down(), 2, &pbrush);
+ }
+}
+
+ModulePort *StructurePort::portAt(int segment, int x, int y)
+{
+ assert(segment == 0);
+
+ QPoint clickpoint(x,y);
+ if(_port->clickrect.contains(clickpoint)) return _port;
+ return 0;
+}
+
+void StructurePort::dumpPorts(list<ModulePort *>& ports)
+{
+ ports.push_back(_port);
+}
+
+QPixmap *StructurePort::pixmap()
+{
+ return 0;
+}
+
+QString StructurePort::name()
+{
+ return QString::fromLocal8Bit(SPortDesc.name().c_str());
+}
+
+void StructurePort::raisePosition()
+{
+ SPortDesc.raisePosition();
+}
+
+void StructurePort::lowerPosition()
+{
+ SPortDesc.lowerPosition();
+}
+
+void StructurePort::rename(const char *newname)
+{
+ SPortDesc.rename(newname);
+ canvas->redrawRect(_x,_y,1,1);
+}
+
+long StructurePort::id()
+{
+ return SPortDesc.ID();
+}
+
+long StructurePort::position()
+{
+ return SPortDesc.position();
+}
+
+ModulePort *StructurePort::port()
+{
+ return _port;
+}
+
+const char *StructurePort::inheritedInterface()
+{
+ static string ii;
+ ii = SPortDesc.inheritedInterface();
+ return ii.c_str();
+}
+
+void StructurePort::inheritedInterface(const char *iface)
+{
+ SPortDesc.inheritedInterface(iface);
+}
diff --git a/arts/builder/structureport.h b/arts/builder/structureport.h
new file mode 100644
index 00000000..3eac37a4
--- /dev/null
+++ b/arts/builder/structureport.h
@@ -0,0 +1,66 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef STRUCTUREPORT_H
+#define STRUCTUREPORT_H
+
+#include "scomponent.h"
+#include "module.h"
+
+class StructurePort :public StructureComponent {
+protected:
+ Arts::StructurePortDesc SPortDesc;
+ Arts::StructureDesc StructureDesc;
+
+ ModulePort *_port;
+
+ bool moveInternal(int x, int y);
+
+public:
+ StructurePort( Arts::StructurePortDesc SPortDesc,
+ Arts::StructureDesc StructureDesc, StructureCanvas *canvas);
+ ~StructurePort();
+
+ void raisePosition();
+ void lowerPosition();
+ void rename(const char *newname);
+ long id();
+ long position();
+ ModulePort *port();
+
+ const char *inheritedInterface();
+ void inheritedInterface(const char *iface);
+
+ // StructureComponent Interface
+ int width() const;
+ int height() const;
+ ComponentType type();
+
+ ModulePort *portAt(int segment, int x, int y);
+ void dumpPorts(std::list<ModulePort *>& ports);
+
+ bool drawNeedsBackground(int segment);
+ void drawSegment(QPainter *dest, int cellsize, int segment);
+ QPixmap *pixmap();
+ QString name();
+};
+
+#endif // STRUCTUREPORT_H
diff --git a/arts/builder/x-artsbuilder.desktop b/arts/builder/x-artsbuilder.desktop
new file mode 100644
index 00000000..684125ae
--- /dev/null
+++ b/arts/builder/x-artsbuilder.desktop
@@ -0,0 +1,60 @@
+# KDE Config File
+[Desktop Entry]
+MimeType=application/x-artsbuilder
+Comment=Arts Builder
+Comment[ar]=أداة لبناء الأصوات باستخدام aRts
+Comment[bg]=Аудио дизайнер
+Comment[bn]=আর্ট্‌স্ বিল্ডার
+Comment[br]=Arload Arts Builder
+Comment[ca]=Constructor Arts
+Comment[cs]=Konstruktér aRts
+Comment[cy]=Adeiladwr Arts
+Comment[da]=aRts-bygger
+Comment[de]=Arts-Builder
+Comment[eo]=Arts-Kreilo
+Comment[es]=Arts Builder (diseñador del sintetizador aRts)
+Comment[et]=aRts'i generaator
+Comment[fa]=سازندۀ Arts
+Comment[fi]=Arts-rakentaja
+Comment[fr]=Créateur de synthétiseurs d'aRts
+Comment[ga]=Tógálaí Arts
+Comment[gl]=Constructor Arts
+Comment[he]=בנאי של Arts
+Comment[hi]=एआरटीएस बिल्डर
+Comment[hu]=aRts-alapú hangmodellező program
+Comment[id]=Builder Arts
+Comment[is]=Arts smiður
+Comment[it]=Costruttore per aRts
+Comment[ja]=aRts ビルダー
+Comment[kk]=Arts құрастырғышы
+Comment[km]=កម្មវិធី​បង្កើត Arts
+Comment[ko]=Arts 만들기
+Comment[lt]=Arts komponuoklis
+Comment[mk]=Градител на Arts
+Comment[mt]=Bennej Arts
+Comment[nb]=Arts-bygger
+Comment[nds]=Klangfiltern för aRts
+Comment[ne]=कला निर्माता
+Comment[nl]=Arts Bouwprogramma
+Comment[nn]=Arts-byggjar
+Comment[pa]=Arts ਨਿਰਮਾਤਾ
+Comment[pt]=Construtor do Arts
+Comment[pt_BR]=Construtor Arts
+Comment[ru]=Звуковой дизайнер aRts
+Comment[se]=Arts-huksejeaddji
+Comment[sl]=Graditelj Arts
+Comment[sr]=Градитељ Arts-а
+Comment[sr@Latn]=Graditelj Arts-a
+Comment[sv]=Arts-byggare
+Comment[ta]=கலைத்திறன் உருவாக்குபவர்
+Comment[tg]=Созандаи aRts
+Comment[tr]=Arts Oluşturucu
+Comment[ven]=Muiti wa zwavhutsila
+Comment[xh]=Umakhi wemizobo
+Comment[zh_CN]=Arts 构建程序
+Comment[zu]=Umakhi Wezamasiko
+Icon=arts
+Type=MimeType
+Patterns=*.arts;
+OnlyShowIn=KDE;
+X-KDE-AutoEmbed=false
diff --git a/arts/configure.in.in b/arts/configure.in.in
new file mode 100644
index 00000000..e76c7e40
--- /dev/null
+++ b/arts/configure.in.in
@@ -0,0 +1,60 @@
+
+if test "x$build_arts" = "xno"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE arts"
+fi
+
+dnl Find aRts using artsc-config
+AC_DEFUN([AC_FIND_ARTS],
+[
+ AC_PATH_PROG(ARTSCCONFIG, artsc-config, no)
+ if test "x$ARTSCCONFIG" = "xno" ; then
+ AC_MSG_ERROR(Cannot find artsc-config - missing from path?)
+ fi
+ ARTSDIR=[`$ARTSCCONFIG --arts-prefix`]
+])
+
+KDE_CHECK_THREADING
+
+dnl Check if we are building as part of KDE.
+
+AC_MSG_CHECKING(if building standalone aRts snapshot without KDE)
+if test "$DCOPIDL" = ""; then
+ AC_MSG_RESULT(yes)
+
+ AC_FIND_ARTS
+
+ dnl find mcopidl
+ MCOPIDL="$ARTSDIR/bin/mcopidl"
+ AC_SUBST(MCOPIDL)
+
+ dnl fake KDE_RPATH, moc, uic
+ KDE_RPATH=""
+ MOC=true
+ UIC=true
+ AC_SUBST(KDE_RPATH)
+ AC_SUBST(MOC)
+ AC_SUBST(UIC)
+
+ dnl variables
+ arts_datadir="$ARTSDIR/share"
+ arts_includes="$ARTSDIR/include/arts"
+ arts_libraries="$ARTSDIR/lib"
+ ARTS_BUILD_KDE=""
+ ARTS_BUILD_KDE_GUI=""
+else
+ AC_MSG_RESULT(no)
+
+ dnl variables
+ arts_datadir="$kde_datadir"
+ arts_includes="$kde_includes/arts"
+ arts_libraries="$kde_libraries"
+
+ dnl conditional build some things
+ ARTS_BUILD_KDE="builder tools"
+ ARTS_BUILD_KDE_GUI="kde"
+fi
+
+AC_SUBST(arts_datadir)
+AC_SUBST(arts_includes)
+AC_SUBST(arts_libraries)
+AM_CONDITIONAL(arts_within_KDE, test -n "$ARTS_BUILD_KDE")
diff --git a/arts/examples/Makefile.am b/arts/examples/Makefile.am
new file mode 100644
index 00000000..b39302ed
--- /dev/null
+++ b/arts/examples/Makefile.am
@@ -0,0 +1,73 @@
+arts_examples_DATA = \
+README \
+example_adsr.arts \
+example_atan_saturate.arts \
+example_autopanner.arts \
+example_brickwall.arts \
+example_bus.arts \
+example_capture_wav.arts \
+example_cdelay.arts \
+example_cflanger.arts \
+example_data.arts \
+example_delay.arts \
+example_dtmf1.arts \
+example_equalizer.arts \
+example_fm.arts \
+example_freeverb.arts \
+example_moog.arts \
+example_multi_add.arts \
+example_noise.arts \
+example_pitchshift.arts \
+example_play_wave.arts \
+example_pscale.arts \
+example_pulse.arts \
+example_rc.arts \
+example_record.arts \
+example_sequence.arts \
+example_shelve_cutoff.arts \
+example_sine.arts \
+example_softsaw.arts \
+example_square.arts \
+example_stereobeep.arts \
+example_tremolo.arts \
+example_tri.arts \
+example_xfade.arts \
+instrument_full_square.arts \
+instrument_hihat.arts \
+instrument_neworgan.arts \
+instrument_nokind.arts \
+instrument_organ2.arts \
+instrument_simple_sin.arts \
+instrument_simple_square.arts \
+instrument_simple_tri.arts \
+instrument_slide.arts \
+instrument_slide1.arts \
+instrument_square.arts \
+instrument_tri.arts \
+template_Empty_Structure.arts \
+template_Instrument.arts \
+instrument_arts_all.arts-map \
+instrument_chirpdrum.arts \
+instrument_deepdrum.arts
+
+arts_examplesdir = $(arts_datadir)/artsbuilder/examples
+
+todo_DATA = \
+instrument_flexible_slide.arts \
+instrument_flexible_slide_GUI.arts \
+instrument_moog_vcf_tune.arts \
+instrument_moog_vcf_tune_GUI.arts \
+instrument_fm_horn.arts \
+effect_delay.arts \
+effect_delay_alone.arts \
+effect_flanger_alone.arts \
+mixer_element_simple.arts \
+mixer_element_eq.arts \
+mixer_element_eqfx.arts \
+template_Instrument_GUI.arts \
+template_Mixer_Element.arts
+
+tododir = $(arts_datadir)/artsbuilder/examples/todo
+
+
+EXTRA_DIST = $(arts_examples_DATA)
diff --git a/arts/examples/README b/arts/examples/README
new file mode 100644
index 00000000..2132bfc3
--- /dev/null
+++ b/arts/examples/README
@@ -0,0 +1,256 @@
+Example Arts Modules
+--------------------
+
+This directory contains example arts modules. The examples fall into
+several categories:
+
+1. Effects which can be used as reusable building blocks (named
+ effect_*.arts)
+
+2. Standalone examples illustrating how to use each of the built-in
+ arts modules (named example_*.arts). These typically send some
+ output to a sound card.
+
+3. Instruments built from lower level arts modules (named
+ instrument_*.arts). These following a standard convention for
+ input and output ports so they can be used by a (future) instrument
+ manager.
+
+4. Mixer elements used for creating mixers, including graphical
+ controls (named mixer_element_*.arts).
+
+5. Templates for creating new modules (names template_*.arts).
+
+6. Miscellaneous modules that don't fit into any of the above
+ categories.
+
+Detailed Description Of Each Module
+-----------------------------------
+
+Examples
+--------
+
+example_stereo_beep.arts
+
+Generates a 440Hz sine wave tone in the left channel and an 880Hz sine
+wave tone in the right channel, and sends it to the sound card
+output. This is referenced in the aRts documentation.
+
+example_sine.arts
+
+Generates a 440 Hz sine wave.
+
+example_pulse.arts
+
+Generates a 440 Hz pulse wave with a 20% duty cycle.
+
+example_softsaw.arts
+
+Generates a 440 Hz sawtooth wave.
+
+example_square.arts
+
+Generates a 440 Hz square wave.
+
+example_tri.arts
+
+Generates a 440 Hz triangle wave.
+
+example_noise.arts
+
+Generates white noise.
+
+example_dtmf1.arts
+
+Generates a dual tone by producing 697 and 1209 Hz sine waves, scaling
+them by 0.5, and adding them together. This is the DTMF tone for the
+digit "1" on a telephone keypad.
+
+example_atan_saturate.arts
+
+Runs a triangle wave through the atan saturate filter.
+
+example_autopanner.arts
+
+Uses an autopanner to pan a 400 Hz sine wave between the left and
+right speakers at a 2 Hz rate.
+
+example_brickwall.arts
+
+Scales a sine wave by a factor of 5 and then runs it through a
+brickwall limiter.
+
+example_bus.arts
+
+Downlinks from a bus called "Bus" and uplinks to the bus
+"out_soundcard" with the left and right channels reversed.
+
+example_cdelay.arts
+
+Downlinks from a bus called "Delay", uplinks the right channel through
+a 0.5 second cdelay, and the left channel unchanged. You can use
+artscontrol to connect the effect to a sound player and observe the
+results.
+
+example_delay.arts
+
+This is the same as example_cdelay but used the delay effect.
+
+example_capture_wav.arts
+
+This uses the Synth_CAPTURE_WAV to save a 400 Hz sine wave as a wav
+file. Run the module for a few seconds, and then examine the file
+created in /tmp. You can play the file with a player such as kaiman.
+
+example_data.arts
+
+This uses the Data module to generate a constant stream of the value
+"3" and sends it to a Debug module to periodically display it. It
+also contains a Nil module, illustrating how it can be used to
+do nothing at all.
+
+example_adsr.arts
+
+Shows how to create a simple instrument sound using the Envelope Adsr
+module, repetitively triggered by a square wave.
+
+example_fm.arts
+
+This uses the FM Source module to generate a 440 Hz sine
+wave which is frequency modulated at a 5 Hz rate.
+
+example_freeverb.arts
+
+This connects the Freeverb effect from a bus downlink to a bus
+outlink. You can use artscontrol to connect the effect to a sound
+player and observe the results.
+
+example_flanger.arts
+
+This implements a simple flanger effect (it doesn't appear
+to work yet, though).
+
+example_moog.arts
+
+This structure combines the two channels from a bus into
+one, passes it though the Moog VCF filter, and sends
+it out the out_soundcard bus.
+
+example_pitch_shift.arts
+
+This structure passes the left channel of sound card data through the
+Pitch Shift effect. Adjust the speed parameter to vary the effect.
+
+example_rc.arts
+
+This structure passes a white noise generator though an RC filter and
+out to the sound card. By viewing the FFT Scope display in artscontrol
+you can see how this varies from an unfiltered noise waveform.
+
+example_sequence.arts
+
+This demonstrates the Sequence module by playing a sequence of notes.
+
+example_shelve_cutoff.arts
+
+This structure passes a white noise generator though a Shelve Cutoff
+filter and out to the sound card. By viewing the FFT Scope display in
+artscontrol you can see how this varies from an unfiltered noise
+waveform.
+
+example_equalizer.arts
+
+This demonstrates the Std_Equalizer module. It boosts the low and high
+frequencies by 6 dB.
+
+example_tremolo.arts
+
+This demonstrates the Tremolo effect. It modulates the left and right
+channels using a 10 Hz tremolo.
+
+example_xfade.arts
+
+This example mixes 440 and 880 Hz sine waves using a cross fader.
+Adjust the value of the cross fader's percentage input from -1 to 1 to
+control the mixing of the two signals.
+
+example_pscale.arts
+
+This illustrates the Pscale module (I'm not sure if this is a
+meaningful example).
+
+example_play_wav.arts
+
+This illustrates the Play Wave module. You will need to
+enter the full path to a .wav file as the filename
+parameter.
+
+example_multi_add.arts
+
+This shows the Multi Add module which accepts any number of inputs. It
+sums three Data modules which produce inputs of 1, 2, and 3, and
+displays the result 6.
+
+Instruments
+-----------
+
+instrument_flexible_slide.arts
+
+instrument_flexible_slide_GUI.arts
+
+instrument_fm_horn.arts
+
+instrument_full_square.arts
+
+instrument_moog_vcf_tune.arts
+
+instrument_moog_vcf_tune_GUI.arts
+
+instrument_neworgan.arts
+
+instrument_nokind.arts
+
+instrument_organ2.arts
+
+instrument_simple_sin.arts
+
+instrument_simple_square.arts
+
+instrument_simple_tri.arts
+
+instrument_slide.arts
+
+instrument_slide1.arts
+
+instrument_square.arts
+
+instrument_tri.arts
+
+Effects
+-------
+
+effect_delay.arts
+
+effect_delay_alone.arts
+
+effect_flanger_alone.arts
+
+Templates
+---------
+
+template_Empty_Structure.arts
+
+template_Instrument.arts
+
+template_Instrument_GUI.arts
+
+template_Mixer_Element.arts
+
+Mixer Elements
+--------------
+
+mixer_element_simple.arts
+
+mixer_element_eq.arts
+
+mixer_element_eqfx.arts
diff --git a/arts/examples/TODO b/arts/examples/TODO
new file mode 100644
index 00000000..cc886aff
--- /dev/null
+++ b/arts/examples/TODO
@@ -0,0 +1,2 @@
+- port the remaining aRts 0.3 examples
+- test the instruments (need more MIDI infrastructure to be implemented)
diff --git a/arts/examples/checknames.sh b/arts/examples/checknames.sh
new file mode 100755
index 00000000..8806a9fd
--- /dev/null
+++ b/arts/examples/checknames.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+echo "This script searches for improperly named .arts structures:" >&2
+
+for i in *.arts
+do
+ grep ^name=$(echo $i|sed s/.arts//g) $i >/dev/null || echo $i
+done
+
+echo "... done" >&2
diff --git a/arts/examples/effect_delay.arts b/arts/examples/effect_delay.arts
new file mode 100644
index 00000000..0dfff7fb
--- /dev/null
+++ b/arts/examples/effect_delay.arts
@@ -0,0 +1,310 @@
+name=effect_delay
+module=Synth_RC
+{
+ id=60
+ x=0
+ y=8
+ port=invalue
+ {
+ id=61
+ connect_to=100
+ }
+ port=b
+ {
+ id=62
+ connect_to=83
+ }
+ port=f
+ {
+ id=63
+ connect_to=83
+ }
+ port=outvalue
+ {
+ id=64
+ connect_to=71
+ }
+}
+module=Synth_RC
+{
+ id=65
+ x=4
+ y=8
+ port=invalue
+ {
+ id=66
+ connect_to=116
+ }
+ port=b
+ {
+ id=67
+ connect_to=84
+ }
+ port=f
+ {
+ id=68
+ connect_to=84
+ }
+ port=outvalue
+ {
+ id=69
+ connect_to=75
+ }
+}
+module=Synth_CDELAY
+{
+ id=70
+ x=1
+ y=9
+ port=invalue
+ {
+ id=71
+ connect_to=64
+ }
+ port=time
+ {
+ id=72
+ data=0.2
+ }
+ port=outvalue
+ {
+ id=73
+ connect_to=90
+ }
+}
+module=Synth_CDELAY
+{
+ id=74
+ x=5
+ y=9
+ port=invalue
+ {
+ id=75
+ connect_to=69
+ }
+ port=time
+ {
+ id=76
+ data=0.3
+ }
+ port=outvalue
+ {
+ id=77
+ connect_to=106
+ }
+}
+module=Synth_MUL
+{
+ id=89
+ x=2
+ y=11
+ port=invalue1
+ {
+ id=90
+ connect_to=73
+ }
+ port=invalue2
+ {
+ id=91
+ connect_to=82
+ }
+ port=outvalue
+ {
+ id=92
+ connect_to=115
+ }
+}
+module=Synth_ADD
+{
+ id=97
+ x=0
+ y=3
+ port=invalue
+ {
+ id=98
+ connect_to=78
+ }
+ port=addit
+ {
+ id=99
+ connect_to=108
+ }
+ port=outvalue
+ {
+ id=100
+ connect_to=80
+ connect_to=61
+ }
+}
+module=Synth_MUL
+{
+ id=105
+ x=6
+ y=11
+ port=invalue1
+ {
+ id=106
+ connect_to=77
+ }
+ port=invalue2
+ {
+ id=107
+ connect_to=82
+ }
+ port=outvalue
+ {
+ id=108
+ connect_to=99
+ }
+}
+module=Synth_ADD
+{
+ id=113
+ x=4
+ y=3
+ port=invalue
+ {
+ id=114
+ connect_to=79
+ }
+ port=addit
+ {
+ id=115
+ connect_to=92
+ }
+ port=outvalue
+ {
+ id=116
+ connect_to=66
+ connect_to=81
+ }
+}
+structureport
+{
+ name=inleft
+ x=1
+ y=1
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=78
+ connect_to=98
+ }
+}
+structureport
+{
+ name=inright
+ x=5
+ y=1
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=79
+ connect_to=114
+ }
+}
+structureport
+{
+ name=outleft
+ x=2
+ y=5
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=80
+ connect_to=100
+ }
+}
+structureport
+{
+ name=outright
+ x=6
+ y=5
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=81
+ connect_to=116
+ }
+}
+structureport
+{
+ name=level
+ x=4
+ y=9
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=82
+ connect_to=91
+ connect_to=107
+ }
+}
+structureport
+{
+ name=filter1
+ x=2
+ y=6
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=83
+ connect_to=63
+ connect_to=62
+ }
+}
+structureport
+{
+ name=filter2
+ x=6
+ y=6
+ position=4
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=84
+ connect_to=68
+ connect_to=67
+ }
+}
diff --git a/arts/examples/effect_delay_alone.arts b/arts/examples/effect_delay_alone.arts
new file mode 100644
index 00000000..fbc29b7e
--- /dev/null
+++ b/arts/examples/effect_delay_alone.arts
@@ -0,0 +1,310 @@
+name=effect_delay_alone
+module=Synth_RC
+{
+ id=59
+ x=0
+ y=8
+ port=invalue
+ {
+ id=60
+ connect_to=84
+ }
+ port=b
+ {
+ id=61
+ connect_to=98
+ }
+ port=f
+ {
+ id=62
+ connect_to=98
+ }
+ port=outvalue
+ {
+ id=63
+ connect_to=70
+ }
+}
+module=Synth_RC
+{
+ id=64
+ x=4
+ y=8
+ port=invalue
+ {
+ id=65
+ connect_to=92
+ }
+ port=b
+ {
+ id=66
+ connect_to=99
+ }
+ port=f
+ {
+ id=67
+ connect_to=99
+ }
+ port=outvalue
+ {
+ id=68
+ connect_to=74
+ }
+}
+module=Synth_CDELAY
+{
+ id=69
+ x=1
+ y=9
+ port=invalue
+ {
+ id=70
+ connect_to=63
+ }
+ port=time
+ {
+ id=71
+ data=0.2
+ }
+ port=outvalue
+ {
+ id=72
+ connect_to=78
+ connect_to=95
+ }
+}
+module=Synth_CDELAY
+{
+ id=73
+ x=5
+ y=9
+ port=invalue
+ {
+ id=74
+ connect_to=68
+ }
+ port=time
+ {
+ id=75
+ data=0.3
+ }
+ port=outvalue
+ {
+ id=76
+ connect_to=86
+ connect_to=96
+ }
+}
+module=Synth_MUL
+{
+ id=77
+ x=2
+ y=11
+ port=invalue1
+ {
+ id=78
+ connect_to=72
+ }
+ port=invalue2
+ {
+ id=79
+ connect_to=97
+ }
+ port=outvalue
+ {
+ id=80
+ connect_to=91
+ }
+}
+module=Synth_ADD
+{
+ id=81
+ x=0
+ y=3
+ port=invalue
+ {
+ id=82
+ connect_to=93
+ }
+ port=addit
+ {
+ id=83
+ connect_to=88
+ }
+ port=outvalue
+ {
+ id=84
+ connect_to=60
+ }
+}
+module=Synth_MUL
+{
+ id=85
+ x=6
+ y=11
+ port=invalue1
+ {
+ id=86
+ connect_to=76
+ }
+ port=invalue2
+ {
+ id=87
+ connect_to=97
+ }
+ port=outvalue
+ {
+ id=88
+ connect_to=83
+ }
+}
+module=Synth_ADD
+{
+ id=89
+ x=4
+ y=3
+ port=invalue
+ {
+ id=90
+ connect_to=94
+ }
+ port=addit
+ {
+ id=91
+ connect_to=80
+ }
+ port=outvalue
+ {
+ id=92
+ connect_to=65
+ }
+}
+structureport
+{
+ name=inleft
+ x=1
+ y=1
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=93
+ connect_to=82
+ }
+}
+structureport
+{
+ name=inright
+ x=5
+ y=1
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=94
+ connect_to=90
+ }
+}
+structureport
+{
+ name=outleft
+ x=1
+ y=11
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=95
+ connect_to=72
+ }
+}
+structureport
+{
+ name=outright
+ x=9
+ y=11
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=96
+ connect_to=76
+ }
+}
+structureport
+{
+ name=level
+ x=4
+ y=9
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=97
+ connect_to=79
+ connect_to=87
+ }
+}
+structureport
+{
+ name=filter1
+ x=2
+ y=6
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=98
+ connect_to=61
+ connect_to=62
+ }
+}
+structureport
+{
+ name=filter2
+ x=6
+ y=6
+ position=4
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=99
+ connect_to=66
+ connect_to=67
+ }
+}
diff --git a/arts/examples/effect_flanger_alone.arts b/arts/examples/effect_flanger_alone.arts
new file mode 100644
index 00000000..c3dc1a63
--- /dev/null
+++ b/arts/examples/effect_flanger_alone.arts
@@ -0,0 +1,285 @@
+name=effect_flanger_alone
+module=Synth_FX_CFLANGER
+{
+ id=0
+ x=0
+ y=7
+ port=invalue
+ {
+ id=1
+ connect_to=18
+ }
+ port=lfo
+ {
+ id=2
+ connect_to=17
+ }
+ port=mintime
+ {
+ id=3
+ connect_to=23
+ }
+ port=maxtime
+ {
+ id=4
+ connect_to=24
+ }
+ port=outvalue
+ {
+ id=5
+ connect_to=30
+ }
+}
+module=Synth_FX_CFLANGER
+{
+ id=6
+ x=6
+ y=7
+ port=invalue
+ {
+ id=7
+ connect_to=19
+ }
+ port=lfo
+ {
+ id=8
+ connect_to=17
+ }
+ port=mintime
+ {
+ id=9
+ connect_to=23
+ }
+ port=maxtime
+ {
+ id=10
+ connect_to=24
+ }
+ port=outvalue
+ {
+ id=11
+ connect_to=39
+ }
+}
+module=Synth_FREQUENCY
+{
+ id=12
+ x=5
+ y=3
+ port=frequency
+ {
+ id=13
+ connect_to=22
+ }
+ port=pos
+ {
+ id=14
+ connect_to=16
+ }
+}
+module=Synth_WAVE_SIN
+{
+ id=15
+ x=6
+ y=4
+ port=pos
+ {
+ id=16
+ connect_to=14
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=2
+ connect_to=8
+ }
+}
+module=Synth_MUL
+{
+ id=29
+ x=2
+ y=9
+ port=invalue1
+ {
+ id=30
+ connect_to=5
+ }
+ port=invalue2
+ {
+ id=31
+ connect_to=41
+ }
+ port=outvalue
+ {
+ id=32
+ connect_to=20
+ }
+}
+module=Synth_MUL
+{
+ id=37
+ x=5
+ y=9
+ port=invalue1
+ {
+ id=38
+ connect_to=41
+ }
+ port=invalue2
+ {
+ id=39
+ connect_to=11
+ }
+ port=outvalue
+ {
+ id=40
+ connect_to=21
+ }
+}
+structureport
+{
+ name=inleft
+ x=1
+ y=6
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=18
+ connect_to=1
+ }
+}
+structureport
+{
+ name=inright
+ x=7
+ y=6
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=19
+ connect_to=7
+ }
+}
+structureport
+{
+ name=outleft
+ x=4
+ y=10
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=20
+ connect_to=32
+ }
+}
+structureport
+{
+ name=outright
+ x=7
+ y=10
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=21
+ connect_to=40
+ }
+}
+structureport
+{
+ name=frequency
+ x=6
+ y=2
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=22
+ connect_to=13
+ }
+}
+structureport
+{
+ name=mintime
+ x=6
+ y=0
+ position=3
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=23
+ connect_to=3
+ connect_to=9
+ }
+}
+structureport
+{
+ name=maxtime
+ x=7
+ y=0
+ position=4
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=24
+ connect_to=4
+ connect_to=10
+ }
+}
+structureport
+{
+ name=level
+ x=6
+ y=8
+ position=5
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=41
+ connect_to=38
+ connect_to=31
+ }
+}
diff --git a/arts/examples/example_adsr.arts b/arts/examples/example_adsr.arts
new file mode 100644
index 00000000..b6a2cdff
--- /dev/null
+++ b/arts/examples/example_adsr.arts
@@ -0,0 +1,137 @@
+name=example_adsr
+module=Arts::Synth_AMAN_PLAY
+{
+ id=0
+ x=1
+ y=7
+ port=title
+ {
+ id=1
+ string_data=Adsr
+ }
+ port=autoRestoreID
+ {
+ id=2
+ string_data=Demo2
+ }
+ port=left
+ {
+ id=3
+ connect_to=21
+ }
+ port=right
+ {
+ id=4
+ connect_to=21
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=5
+ x=5
+ y=3
+ port=pos
+ {
+ id=6
+ connect_to=10
+ }
+ port=outvalue
+ {
+ id=7
+ connect_to=16
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=8
+ x=5
+ y=1
+ port=frequency
+ {
+ id=9
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=10
+ connect_to=6
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=11
+ x=1
+ y=1
+ port=frequency
+ {
+ id=12
+ audio_data=1.00000
+ }
+ port=pos
+ {
+ id=13
+ connect_to=24
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=14
+ x=2
+ y=5
+ port=active
+ {
+ id=15
+ connect_to=25
+ }
+ port=invalue
+ {
+ id=16
+ connect_to=7
+ }
+ port=attack
+ {
+ id=17
+ audio_data=0.10000
+ }
+ port=decay
+ {
+ id=18
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=19
+ audio_data=0.50000
+ }
+ port=release
+ {
+ id=20
+ audio_data=0.10000
+ }
+ port=outvalue
+ {
+ id=21
+ connect_to=3
+ connect_to=4
+ }
+ port=done
+ {
+ id=22
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=23
+ x=1
+ y=3
+ port=pos
+ {
+ id=24
+ connect_to=13
+ }
+ port=outvalue
+ {
+ id=25
+ connect_to=15
+ }
+}
diff --git a/arts/examples/example_atan_saturate.arts b/arts/examples/example_atan_saturate.arts
new file mode 100644
index 00000000..c693b38b
--- /dev/null
+++ b/arts/examples/example_atan_saturate.arts
@@ -0,0 +1,81 @@
+name=example_atan_saturate
+module=Arts::Synth_FREQUENCY
+{
+ id=76
+ x=1
+ y=1
+ port=frequency
+ {
+ id=77
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=78
+ connect_to=89
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=79
+ x=1
+ y=7
+ port=title
+ {
+ id=80
+ string_data=Atan Saturate
+ }
+ port=autoRestoreID
+ {
+ id=81
+ string_data=Atan Saturate
+ }
+ port=left
+ {
+ id=82
+ connect_to=87
+ }
+ port=right
+ {
+ id=83
+ connect_to=87
+ }
+}
+module=Arts::Synth_ATAN_SATURATE
+{
+ id=84
+ x=2
+ y=5
+ port=inscale
+ {
+ id=85
+ audio_data=1.00000
+ }
+ port=invalue
+ {
+ id=86
+ connect_to=90
+ }
+ port=outvalue
+ {
+ id=87
+ connect_to=82
+ connect_to=83
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=88
+ x=2
+ y=3
+ port=pos
+ {
+ id=89
+ connect_to=78
+ }
+ port=outvalue
+ {
+ id=90
+ connect_to=86
+ }
+}
diff --git a/arts/examples/example_autopanner.arts b/arts/examples/example_autopanner.arts
new file mode 100644
index 00000000..0a11a2e7
--- /dev/null
+++ b/arts/examples/example_autopanner.arts
@@ -0,0 +1,117 @@
+name=example_autopanner
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=1
+ port=frequency
+ {
+ id=1
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=2
+ connect_to=4
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=3
+ x=1
+ y=3
+ port=pos
+ {
+ id=4
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=5
+ connect_to=12
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=6
+ x=1
+ y=7
+ port=title
+ {
+ id=7
+ string_data=Autopanner
+ }
+ port=autoRestoreID
+ {
+ id=8
+ string_data=Autopanner
+ }
+ port=left
+ {
+ id=9
+ connect_to=14
+ }
+ port=right
+ {
+ id=10
+ connect_to=15
+ }
+}
+module=Arts::Synth_AUTOPANNER
+{
+ id=11
+ x=2
+ y=5
+ port=invalue
+ {
+ id=12
+ connect_to=5
+ }
+ port=inlfo
+ {
+ id=13
+ connect_to=18
+ }
+ port=outvalue1
+ {
+ id=14
+ connect_to=9
+ }
+ port=outvalue2
+ {
+ id=15
+ connect_to=10
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=16
+ x=5
+ y=3
+ port=pos
+ {
+ id=17
+ connect_to=21
+ }
+ port=outvalue
+ {
+ id=18
+ connect_to=13
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=19
+ x=5
+ y=1
+ port=frequency
+ {
+ id=20
+ audio_data=2.00000
+ }
+ port=pos
+ {
+ id=21
+ connect_to=17
+ }
+}
diff --git a/arts/examples/example_brickwall.arts b/arts/examples/example_brickwall.arts
new file mode 100644
index 00000000..546620e1
--- /dev/null
+++ b/arts/examples/example_brickwall.arts
@@ -0,0 +1,98 @@
+name=example_brickwall
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=1
+ port=frequency
+ {
+ id=1
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=2
+ connect_to=13
+ connect_to=25
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=3
+ x=1
+ y=9
+ port=title
+ {
+ id=4
+ string_data=Brickwall
+ }
+ port=autoRestoreID
+ {
+ id=5
+ string_data=Brickwall
+ }
+ port=left
+ {
+ id=6
+ connect_to=20
+ }
+ port=right
+ {
+ id=7
+ connect_to=20
+ }
+}
+module=Arts::Synth_BRICKWALL_LIMITER
+{
+ id=18
+ x=2
+ y=7
+ port=invalue
+ {
+ id=19
+ connect_to=34
+ }
+ port=outvalue
+ {
+ id=20
+ connect_to=6
+ connect_to=7
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=24
+ x=1
+ y=3
+ port=pos
+ {
+ id=25
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=26
+ connect_to=33
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=31
+ x=1
+ y=5
+ port=invalue1
+ {
+ id=32
+ audio_data=5.00000
+ }
+ port=invalue2
+ {
+ id=33
+ connect_to=26
+ }
+ port=outvalue
+ {
+ id=34
+ connect_to=19
+ }
+}
diff --git a/arts/examples/example_bus.arts b/arts/examples/example_bus.arts
new file mode 100644
index 00000000..2a43e84a
--- /dev/null
+++ b/arts/examples/example_bus.arts
@@ -0,0 +1,44 @@
+name=example_bus
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=0
+ x=1
+ y=1
+ port=busname
+ {
+ id=1
+ string_data=Bus
+ }
+ port=left
+ {
+ id=2
+ connect_to=7
+ }
+ port=right
+ {
+ id=3
+ connect_to=10
+ connect_to=6
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=4
+ x=1
+ y=4
+ port=busname
+ {
+ id=5
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=6
+ connect_to=3
+ }
+ port=right
+ {
+ id=7
+ connect_to=2
+ }
+}
diff --git a/arts/examples/example_capture_wav.arts b/arts/examples/example_capture_wav.arts
new file mode 100644
index 00000000..0638e64a
--- /dev/null
+++ b/arts/examples/example_capture_wav.arts
@@ -0,0 +1,50 @@
+name=example_capture_wav
+module=Arts::Synth_CAPTURE_WAV
+{
+ id=3
+ x=1
+ y=5
+ port=left
+ {
+ id=4
+ connect_to=11
+ }
+ port=right
+ {
+ id=5
+ connect_to=11
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=9
+ x=1
+ y=3
+ port=pos
+ {
+ id=10
+ connect_to=17
+ }
+ port=outvalue
+ {
+ id=11
+ connect_to=4
+ connect_to=5
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=15
+ x=1
+ y=1
+ port=frequency
+ {
+ id=16
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=17
+ connect_to=10
+ }
+}
diff --git a/arts/examples/example_cdelay.arts b/arts/examples/example_cdelay.arts
new file mode 100644
index 00000000..211834b6
--- /dev/null
+++ b/arts/examples/example_cdelay.arts
@@ -0,0 +1,64 @@
+name=example_cdelay
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=0
+ x=1
+ y=1
+ port=busname
+ {
+ id=1
+ string_data=Delay
+ }
+ port=left
+ {
+ id=2
+ connect_to=6
+ }
+ port=right
+ {
+ id=3
+ connect_to=10
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=4
+ x=1
+ y=5
+ port=busname
+ {
+ id=5
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=6
+ connect_to=2
+ }
+ port=right
+ {
+ id=7
+ connect_to=11
+ }
+}
+module=Arts::Synth_CDELAY
+{
+ id=8
+ x=4
+ y=3
+ port=time
+ {
+ id=9
+ audio_data=0.50000
+ }
+ port=invalue
+ {
+ id=10
+ connect_to=3
+ }
+ port=outvalue
+ {
+ id=11
+ connect_to=7
+ }
+}
diff --git a/arts/examples/example_cflanger.arts b/arts/examples/example_cflanger.arts
new file mode 100644
index 00000000..7f8c2258
--- /dev/null
+++ b/arts/examples/example_cflanger.arts
@@ -0,0 +1,127 @@
+name=example_cflanger
+module=Arts::Synth_FX_CFLANGER
+{
+ id=11
+ x=1
+ y=5
+ port=mintime
+ {
+ id=12
+ audio_data=0.00100
+ }
+ port=maxtime
+ {
+ id=13
+ audio_data=0.00500
+ }
+ port=invalue
+ {
+ id=14
+ connect_to=29
+ }
+ port=lfo
+ {
+ id=15
+ connect_to=19
+ }
+ port=outvalue
+ {
+ id=16
+ connect_to=36
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=17
+ x=8
+ y=3
+ port=pos
+ {
+ id=18
+ connect_to=22
+ }
+ port=outvalue
+ {
+ id=19
+ connect_to=15
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=20
+ x=8
+ y=1
+ port=frequency
+ {
+ id=21
+ audio_data=1.00000
+ }
+ port=pos
+ {
+ id=22
+ connect_to=18
+ }
+}
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=27
+ x=1
+ y=1
+ port=busname
+ {
+ id=28
+ string_data=Flanger
+ }
+ port=left
+ {
+ id=29
+ connect_to=14
+ connect_to=37
+ }
+ port=right
+ {
+ id=30
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=35
+ x=5
+ y=7
+ port=invalue1
+ {
+ id=36
+ connect_to=16
+ }
+ port=invalue2
+ {
+ id=37
+ connect_to=29
+ }
+ port=outvalue
+ {
+ id=38
+ connect_to=9
+ connect_to=45
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=43
+ x=1
+ y=9
+ port=busname
+ {
+ id=44
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=45
+ connect_to=38
+ }
+ port=right
+ {
+ id=46
+ }
+}
diff --git a/arts/examples/example_data.arts b/arts/examples/example_data.arts
new file mode 100644
index 00000000..135c7778
--- /dev/null
+++ b/arts/examples/example_data.arts
@@ -0,0 +1,39 @@
+name=example_data
+module=Arts::Synth_DATA
+{
+ id=3
+ x=1
+ y=1
+ port=value
+ {
+ id=4
+ audio_data=3.00000
+ }
+ port=outvalue
+ {
+ id=5
+ connect_to=11
+ }
+}
+module=Arts::Synth_DEBUG
+{
+ id=9
+ x=1
+ y=3
+ port=comment
+ {
+ id=10
+ string_data=Data:
+ }
+ port=invalue
+ {
+ id=11
+ connect_to=5
+ }
+}
+module=Arts::Synth_NIL
+{
+ id=13
+ x=5
+ y=1
+}
diff --git a/arts/examples/example_delay.arts b/arts/examples/example_delay.arts
new file mode 100644
index 00000000..c7339a5c
--- /dev/null
+++ b/arts/examples/example_delay.arts
@@ -0,0 +1,65 @@
+name=example_delay
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=0
+ x=1
+ y=1
+ port=busname
+ {
+ id=1
+ string_data=Delay
+ }
+ port=left
+ {
+ id=2
+ connect_to=6
+ }
+ port=right
+ {
+ id=3
+ connect_to=10
+ connect_to=17
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=4
+ x=1
+ y=5
+ port=busname
+ {
+ id=5
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=6
+ connect_to=2
+ }
+ port=right
+ {
+ id=7
+ connect_to=19
+ }
+}
+module=Arts::Synth_DELAY
+{
+ id=16
+ x=4
+ y=3
+ port=invalue
+ {
+ id=17
+ connect_to=3
+ }
+ port=time
+ {
+ id=18
+ audio_data=0.50000
+ }
+ port=outvalue
+ {
+ id=19
+ connect_to=7
+ }
+}
diff --git a/arts/examples/example_dtmf1.arts b/arts/examples/example_dtmf1.arts
new file mode 100644
index 00000000..8adcb628
--- /dev/null
+++ b/arts/examples/example_dtmf1.arts
@@ -0,0 +1,155 @@
+name=example_dtmf1
+module=Arts::Synth_AMAN_PLAY
+{
+ id=0
+ x=2
+ y=8
+ port=title
+ {
+ id=1
+ string_data=Dtmf1
+ }
+ port=autoRestoreID
+ {
+ id=2
+ string_data=Dtmf1
+ }
+ port=left
+ {
+ id=3
+ connect_to=14
+ }
+ port=right
+ {
+ id=4
+ connect_to=14
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=5
+ x=1
+ y=2
+ port=pos
+ {
+ id=6
+ connect_to=10
+ }
+ port=outvalue
+ {
+ id=7
+ connect_to=23
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=8
+ x=1
+ y=0
+ port=frequency
+ {
+ id=9
+ audio_data=697.00000
+ }
+ port=pos
+ {
+ id=10
+ connect_to=6
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=11
+ x=3
+ y=6
+ port=invalue1
+ {
+ id=12
+ connect_to=24
+ }
+ port=invalue2
+ {
+ id=13
+ connect_to=28
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=3
+ connect_to=4
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=15
+ x=5
+ y=2
+ port=pos
+ {
+ id=16
+ connect_to=20
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=27
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=18
+ x=5
+ y=0
+ port=frequency
+ {
+ id=19
+ audio_data=1209.00000
+ }
+ port=pos
+ {
+ id=20
+ connect_to=16
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=21
+ x=1
+ y=4
+ port=invalue1
+ {
+ id=22
+ audio_data=0.50000
+ }
+ port=invalue2
+ {
+ id=23
+ connect_to=7
+ }
+ port=outvalue
+ {
+ id=24
+ connect_to=12
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=25
+ x=5
+ y=4
+ port=invalue1
+ {
+ id=26
+ audio_data=0.50000
+ }
+ port=invalue2
+ {
+ id=27
+ connect_to=17
+ }
+ port=outvalue
+ {
+ id=28
+ connect_to=13
+ }
+}
diff --git a/arts/examples/example_equalizer.arts b/arts/examples/example_equalizer.arts
new file mode 100644
index 00000000..fe89cea8
--- /dev/null
+++ b/arts/examples/example_equalizer.arts
@@ -0,0 +1,84 @@
+name=example_equalizer
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=0
+ x=1
+ y=1
+ port=busname
+ {
+ id=1
+ string_data=Equalizer
+ }
+ port=left
+ {
+ id=2
+ connect_to=14
+ }
+ port=right
+ {
+ id=3
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=4
+ x=1
+ y=5
+ port=busname
+ {
+ id=5
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=6
+ connect_to=15
+ }
+ port=right
+ {
+ id=7
+ connect_to=15
+ }
+}
+module=Arts::Synth_STD_EQUALIZER
+{
+ id=8
+ x=1
+ y=3
+ port=low
+ {
+ id=9
+ audio_data=6.00000
+ }
+ port=mid
+ {
+ id=10
+ audio_data=0.00000
+ }
+ port=high
+ {
+ id=11
+ audio_data=6.00000
+ }
+ port=frequency
+ {
+ id=12
+ audio_data=1000.00000
+ }
+ port=q
+ {
+ id=13
+ audio_data=1.00000
+ }
+ port=invalue
+ {
+ id=14
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=15
+ connect_to=6
+ connect_to=7
+ }
+}
diff --git a/arts/examples/example_fm.arts b/arts/examples/example_fm.arts
new file mode 100644
index 00000000..242519c0
--- /dev/null
+++ b/arts/examples/example_fm.arts
@@ -0,0 +1,102 @@
+name=example_fm
+module=Arts::Synth_AMAN_PLAY
+{
+ id=36
+ x=1
+ y=9
+ port=title
+ {
+ id=37
+ string_data=Demo1
+ }
+ port=autoRestoreID
+ {
+ id=38
+ string_data=Demo2
+ }
+ port=left
+ {
+ id=39
+ connect_to=43
+ }
+ port=right
+ {
+ id=40
+ connect_to=43
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=41
+ x=2
+ y=7
+ port=pos
+ {
+ id=42
+ connect_to=54
+ }
+ port=outvalue
+ {
+ id=43
+ connect_to=39
+ connect_to=40
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=44
+ x=1
+ y=3
+ port=pos
+ {
+ id=45
+ connect_to=49
+ }
+ port=outvalue
+ {
+ id=46
+ connect_to=52
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=47
+ x=1
+ y=1
+ port=frequency
+ {
+ id=48
+ audio_data=5.00000
+ }
+ port=pos
+ {
+ id=49
+ connect_to=45
+ }
+}
+module=Arts::Synth_FM_SOURCE
+{
+ id=50
+ x=1
+ y=5
+ port=frequency
+ {
+ id=51
+ audio_data=440.00000
+ }
+ port=modulator
+ {
+ id=52
+ connect_to=46
+ }
+ port=modlevel
+ {
+ id=53
+ audio_data=0.90000
+ }
+ port=pos
+ {
+ id=54
+ connect_to=42
+ }
+}
diff --git a/arts/examples/example_freeverb.arts b/arts/examples/example_freeverb.arts
new file mode 100644
index 00000000..b8d3a321
--- /dev/null
+++ b/arts/examples/example_freeverb.arts
@@ -0,0 +1,99 @@
+name=example_freeverb
+module=Arts::Synth_FREEVERB
+{
+ id=0
+ x=1
+ y=3
+ port=inleft
+ {
+ id=1
+ connect_to=13
+ }
+ port=inright
+ {
+ id=2
+ connect_to=14
+ }
+ port=outleft
+ {
+ id=3
+ connect_to=17
+ }
+ port=outright
+ {
+ id=4
+ connect_to=18
+ }
+ port=roomsize
+ {
+ id=5
+ audio_data=1.00000
+ }
+ port=damp
+ {
+ id=6
+ audio_data=0.20000
+ }
+ port=wet
+ {
+ id=7
+ audio_data=0.20000
+ }
+ port=dry
+ {
+ id=8
+ audio_data=0.20000
+ }
+ port=width
+ {
+ id=9
+ audio_data=1.00000
+ }
+ port=mode
+ {
+ id=10
+ audio_data=0.00000
+ }
+}
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=11
+ x=1
+ y=1
+ port=busname
+ {
+ id=12
+ string_data=Freeverb
+ }
+ port=left
+ {
+ id=13
+ connect_to=1
+ }
+ port=right
+ {
+ id=14
+ connect_to=2
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=15
+ x=1
+ y=5
+ port=busname
+ {
+ id=16
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=17
+ connect_to=3
+ }
+ port=right
+ {
+ id=18
+ connect_to=4
+ }
+}
diff --git a/arts/examples/example_moog.arts b/arts/examples/example_moog.arts
new file mode 100644
index 00000000..3a6a0586
--- /dev/null
+++ b/arts/examples/example_moog.arts
@@ -0,0 +1,96 @@
+name=example_moog
+module=Arts::Synth_MOOG_VCF
+{
+ id=17
+ x=3
+ y=4
+ port=frequency
+ {
+ id=18
+ audio_data=2000.00000
+ }
+ port=resonance
+ {
+ id=19
+ audio_data=3.00000
+ }
+ port=invalue
+ {
+ id=20
+ connect_to=47
+ }
+ port=outvalue
+ {
+ id=21
+ connect_to=36
+ connect_to=37
+ }
+}
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=26
+ x=3
+ y=0
+ port=busname
+ {
+ id=27
+ string_data=Moog VCF
+ }
+ port=left
+ {
+ id=28
+ connect_to=44
+ }
+ port=right
+ {
+ id=29
+ connect_to=45
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=34
+ x=3
+ y=6
+ port=busname
+ {
+ id=35
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=36
+ connect_to=21
+ }
+ port=right
+ {
+ id=37
+ connect_to=21
+ }
+}
+module=Arts::Synth_XFADE
+{
+ id=43
+ x=3
+ y=2
+ port=invalue1
+ {
+ id=44
+ connect_to=28
+ }
+ port=invalue2
+ {
+ id=45
+ connect_to=29
+ }
+ port=percentage
+ {
+ id=46
+ audio_data=0.00000
+ }
+ port=outvalue
+ {
+ id=47
+ connect_to=20
+ }
+}
diff --git a/arts/examples/example_multi_add.arts b/arts/examples/example_multi_add.arts
new file mode 100644
index 00000000..229033bc
--- /dev/null
+++ b/arts/examples/example_multi_add.arts
@@ -0,0 +1,83 @@
+name=example_multi_add
+module=Arts::Synth_MULTI_ADD
+{
+ id=3
+ x=2
+ y=3
+ port=invalue
+ {
+ id=4
+ connect_to=11
+ connect_to=17
+ connect_to=23
+ }
+ port=outvalue
+ {
+ id=5
+ connect_to=29
+ }
+}
+module=Arts::Synth_DATA
+{
+ id=9
+ x=1
+ y=1
+ port=value
+ {
+ id=10
+ audio_data=1.00000
+ }
+ port=outvalue
+ {
+ id=11
+ connect_to=4
+ }
+}
+module=Arts::Synth_DATA
+{
+ id=15
+ x=5
+ y=1
+ port=value
+ {
+ id=16
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=4
+ }
+}
+module=Arts::Synth_DATA
+{
+ id=21
+ x=9
+ y=1
+ port=value
+ {
+ id=22
+ audio_data=3.00000
+ }
+ port=outvalue
+ {
+ id=23
+ connect_to=4
+ }
+}
+module=Arts::Synth_DEBUG
+{
+ id=27
+ x=1
+ y=5
+ port=comment
+ {
+ id=28
+ string_data=Result
+ }
+ port=invalue
+ {
+ id=29
+ connect_to=5
+ }
+}
diff --git a/arts/examples/example_noise.arts b/arts/examples/example_noise.arts
new file mode 100644
index 00000000..60f6e2e3
--- /dev/null
+++ b/arts/examples/example_noise.arts
@@ -0,0 +1,39 @@
+name=example_noise
+module=Arts::Synth_AMAN_PLAY
+{
+ id=3
+ x=1
+ y=3
+ port=title
+ {
+ id=4
+ string_data=Noise
+ }
+ port=autoRestoreID
+ {
+ id=5
+ string_data=Noise
+ }
+ port=left
+ {
+ id=6
+ connect_to=15
+ }
+ port=right
+ {
+ id=7
+ connect_to=15
+ }
+}
+module=Arts::Synth_NOISE
+{
+ id=14
+ x=1
+ y=1
+ port=outvalue
+ {
+ id=15
+ connect_to=6
+ connect_to=7
+ }
+}
diff --git a/arts/examples/example_pitchshift.arts b/arts/examples/example_pitchshift.arts
new file mode 100644
index 00000000..5126e54b
--- /dev/null
+++ b/arts/examples/example_pitchshift.arts
@@ -0,0 +1,69 @@
+name=example_pitchshift
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=23
+ x=1
+ y=1
+ port=busname
+ {
+ id=24
+ string_data=Pitch Shift
+ }
+ port=left
+ {
+ id=25
+ connect_to=34
+ }
+ port=right
+ {
+ id=26
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=27
+ x=1
+ y=5
+ port=busname
+ {
+ id=28
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=29
+ connect_to=35
+ }
+ port=right
+ {
+ id=30
+ connect_to=35
+ }
+}
+module=Arts::Synth_PITCH_SHIFT
+{
+ id=31
+ x=1
+ y=3
+ port=speed
+ {
+ id=32
+ audio_data=0.75000
+ }
+ port=frequency
+ {
+ id=33
+ audio_data=10.00000
+ }
+ port=invalue
+ {
+ id=34
+ connect_to=25
+ }
+ port=outvalue
+ {
+ id=35
+ connect_to=29
+ connect_to=30
+ }
+}
diff --git a/arts/examples/example_play_wave.arts b/arts/examples/example_play_wave.arts
new file mode 100644
index 00000000..7a85423d
--- /dev/null
+++ b/arts/examples/example_play_wave.arts
@@ -0,0 +1,57 @@
+name=example_play_wave
+module=Arts::Synth_PLAY_WAV
+{
+ id=6
+ x=1
+ y=1
+ port=speed
+ {
+ id=7
+ audio_data=44100.00000
+ }
+ port=filename
+ {
+ id=8
+ string_data=/home/tranter/test.wav
+ }
+ port=finished
+ {
+ id=9
+ }
+ port=left
+ {
+ id=10
+ connect_to=20
+ }
+ port=right
+ {
+ id=11
+ connect_to=21
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=17
+ x=1
+ y=3
+ port=title
+ {
+ id=18
+ string_data=Wave
+ }
+ port=autoRestoreID
+ {
+ id=19
+ string_data=Wave
+ }
+ port=left
+ {
+ id=20
+ connect_to=10
+ }
+ port=right
+ {
+ id=21
+ connect_to=11
+ }
+}
diff --git a/arts/examples/example_pscale.arts b/arts/examples/example_pscale.arts
new file mode 100644
index 00000000..6f364135
--- /dev/null
+++ b/arts/examples/example_pscale.arts
@@ -0,0 +1,112 @@
+name=example_pscale
+module=Arts::Synth_SEQUENCE
+{
+ id=10
+ x=1
+ y=1
+ port=speed
+ {
+ id=11
+ audio_data=0.50000
+ }
+ port=seq
+ {
+ id=12
+ string_data=C-4;D-4;E-4;F-4;G-4;A-4;B-4;C-5;
+ }
+ port=frequency
+ {
+ id=13
+ connect_to=21
+ }
+ port=pos
+ {
+ id=14
+ connect_to=34
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=15
+ x=1
+ y=8
+ port=title
+ {
+ id=16
+ string_data=Pscale
+ }
+ port=autoRestoreID
+ {
+ id=17
+ string_data=Pscale
+ }
+ port=left
+ {
+ id=18
+ connect_to=35
+ }
+ port=right
+ {
+ id=19
+ connect_to=35
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=20
+ x=1
+ y=3
+ port=frequency
+ {
+ id=21
+ connect_to=13
+ }
+ port=pos
+ {
+ id=22
+ connect_to=24
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=23
+ x=1
+ y=5
+ port=pos
+ {
+ id=24
+ connect_to=22
+ }
+ port=outvalue
+ {
+ id=25
+ connect_to=33
+ }
+}
+module=Arts::Synth_PSCALE
+{
+ id=31
+ x=5
+ y=6
+ port=top
+ {
+ id=32
+ audio_data=0.50000
+ }
+ port=invalue
+ {
+ id=33
+ connect_to=25
+ }
+ port=pos
+ {
+ id=34
+ connect_to=14
+ }
+ port=outvalue
+ {
+ id=35
+ connect_to=18
+ connect_to=19
+ }
+}
diff --git a/arts/examples/example_pulse.arts b/arts/examples/example_pulse.arts
new file mode 100644
index 00000000..7da74675
--- /dev/null
+++ b/arts/examples/example_pulse.arts
@@ -0,0 +1,66 @@
+name=example_pulse
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=1
+ port=frequency
+ {
+ id=1
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=2
+ connect_to=7
+ connect_to=23
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=12
+ x=1
+ y=5
+ port=title
+ {
+ id=13
+ string_data=Pulse
+ }
+ port=autoRestoreID
+ {
+ id=14
+ string_data=Pulse
+ }
+ port=left
+ {
+ id=15
+ connect_to=24
+ }
+ port=right
+ {
+ id=16
+ connect_to=24
+ }
+}
+module=Arts::Synth_WAVE_PULSE
+{
+ id=21
+ x=2
+ y=3
+ port=dutycycle
+ {
+ id=22
+ audio_data=0.20000
+ }
+ port=pos
+ {
+ id=23
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=24
+ connect_to=15
+ connect_to=16
+ }
+}
diff --git a/arts/examples/example_rc.arts b/arts/examples/example_rc.arts
new file mode 100644
index 00000000..bef5a662
--- /dev/null
+++ b/arts/examples/example_rc.arts
@@ -0,0 +1,63 @@
+name=example_rc
+module=Arts::Synth_NOISE
+{
+ id=45
+ x=4
+ y=1
+ port=outvalue
+ {
+ id=46
+ connect_to=60
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=47
+ x=2
+ y=5
+ port=title
+ {
+ id=48
+ }
+ port=autoRestoreID
+ {
+ id=49
+ }
+ port=left
+ {
+ id=50
+ connect_to=61
+ }
+ port=right
+ {
+ id=51
+ connect_to=61
+ }
+}
+module=Arts::Synth_RC
+{
+ id=57
+ x=3
+ y=3
+ port=b
+ {
+ id=58
+ audio_data=10.00000
+ }
+ port=f
+ {
+ id=59
+ audio_data=10.00000
+ }
+ port=invalue
+ {
+ id=60
+ connect_to=46
+ }
+ port=outvalue
+ {
+ id=61
+ connect_to=50
+ connect_to=51
+ }
+}
diff --git a/arts/examples/example_record.arts b/arts/examples/example_record.arts
new file mode 100644
index 00000000..62c365a9
--- /dev/null
+++ b/arts/examples/example_record.arts
@@ -0,0 +1,75 @@
+name=example_record
+module=Arts::Synth_DEBUG
+{
+ id=13
+ x=4
+ y=3
+ port=comment
+ {
+ id=14
+ string_data=Left
+ }
+ port=invalue
+ {
+ id=15
+ }
+}
+module=Arts::Synth_DEBUG
+{
+ id=19
+ x=8
+ y=3
+ port=comment
+ {
+ id=20
+ string_data=Right
+ }
+ port=invalue
+ {
+ id=21
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=27
+ x=1
+ y=5
+ port=title
+ {
+ id=28
+ }
+ port=autoRestoreID
+ {
+ id=29
+ }
+ port=left
+ {
+ id=30
+ }
+ port=right
+ {
+ id=31
+ }
+}
+module=Arts::Synth_AMAN_RECORD
+{
+ id=56
+ x=1
+ y=1
+ port=title
+ {
+ id=57
+ }
+ port=autoRestoreID
+ {
+ id=58
+ }
+ port=left
+ {
+ id=59
+ }
+ port=right
+ {
+ id=60
+ }
+}
diff --git a/arts/examples/example_sequence.arts b/arts/examples/example_sequence.arts
new file mode 100644
index 00000000..2840657e
--- /dev/null
+++ b/arts/examples/example_sequence.arts
@@ -0,0 +1,85 @@
+name=example_sequence
+module=Arts::Synth_SEQUENCE
+{
+ id=0
+ x=3
+ y=1
+ port=speed
+ {
+ id=1
+ audio_data=0.50000
+ }
+ port=seq
+ {
+ id=2
+ string_data=C-4;D-4;E-4;F-4;G-4;A-4;B-4;C-5;
+ }
+ port=frequency
+ {
+ id=3
+ connect_to=11
+ }
+ port=pos
+ {
+ id=4
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=5
+ x=2
+ y=7
+ port=title
+ {
+ id=6
+ string_data=Sequence
+ }
+ port=autoRestoreID
+ {
+ id=7
+ string_data=Sequence
+ }
+ port=left
+ {
+ id=8
+ connect_to=15
+ }
+ port=right
+ {
+ id=9
+ connect_to=15
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=10
+ x=4
+ y=3
+ port=frequency
+ {
+ id=11
+ connect_to=3
+ }
+ port=pos
+ {
+ id=12
+ connect_to=14
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=13
+ x=4
+ y=5
+ port=pos
+ {
+ id=14
+ connect_to=12
+ }
+ port=outvalue
+ {
+ id=15
+ connect_to=8
+ connect_to=9
+ }
+}
diff --git a/arts/examples/example_shelve_cutoff.arts b/arts/examples/example_shelve_cutoff.arts
new file mode 100644
index 00000000..788a6dd3
--- /dev/null
+++ b/arts/examples/example_shelve_cutoff.arts
@@ -0,0 +1,61 @@
+name=example_shelve_cutoff
+module=Arts::Synth_NOISE
+{
+ id=0
+ x=1
+ y=1
+ port=outvalue
+ {
+ id=1
+ connect_to=10
+ connect_to=17
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=2
+ x=1
+ y=5
+ port=title
+ {
+ id=3
+ string_data=Shelve Cutoff
+ }
+ port=autoRestoreID
+ {
+ id=4
+ string_data=Shelve Cutoff
+ }
+ port=left
+ {
+ id=5
+ connect_to=19
+ }
+ port=right
+ {
+ id=6
+ connect_to=19
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=16
+ x=1
+ y=3
+ port=invalue
+ {
+ id=17
+ connect_to=1
+ }
+ port=frequency
+ {
+ id=18
+ audio_data=3000.00000
+ }
+ port=outvalue
+ {
+ id=19
+ connect_to=5
+ connect_to=6
+ }
+}
diff --git a/arts/examples/example_sine.arts b/arts/examples/example_sine.arts
new file mode 100644
index 00000000..5810a23a
--- /dev/null
+++ b/arts/examples/example_sine.arts
@@ -0,0 +1,58 @@
+name=example_sine
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=1
+ port=frequency
+ {
+ id=1
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=2
+ connect_to=7
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=6
+ x=2
+ y=3
+ port=pos
+ {
+ id=7
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=8
+ connect_to=15
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=12
+ x=1
+ y=5
+ port=title
+ {
+ id=13
+ string_data=Sine
+ }
+ port=autoRestoreID
+ {
+ id=14
+ string_data=Sine
+ }
+ port=left
+ {
+ id=15
+ connect_to=8
+ }
+ port=right
+ {
+ id=16
+ }
+}
diff --git a/arts/examples/example_softsaw.arts b/arts/examples/example_softsaw.arts
new file mode 100644
index 00000000..7ab5202c
--- /dev/null
+++ b/arts/examples/example_softsaw.arts
@@ -0,0 +1,61 @@
+name=example_softsaw
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=1
+ port=frequency
+ {
+ id=1
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=2
+ connect_to=10
+ connect_to=16
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=3
+ x=1
+ y=5
+ port=title
+ {
+ id=4
+ string_data=SoftSaw
+ }
+ port=autoRestoreID
+ {
+ id=5
+ string_data=SoftSaw
+ }
+ port=left
+ {
+ id=6
+ connect_to=17
+ }
+ port=right
+ {
+ id=7
+ connect_to=17
+ }
+}
+module=Arts::Synth_WAVE_SOFTSAW
+{
+ id=15
+ x=2
+ y=3
+ port=pos
+ {
+ id=16
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=6
+ connect_to=7
+ }
+}
diff --git a/arts/examples/example_square.arts b/arts/examples/example_square.arts
new file mode 100644
index 00000000..1e0e1d5a
--- /dev/null
+++ b/arts/examples/example_square.arts
@@ -0,0 +1,61 @@
+name=example_square
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=1
+ port=frequency
+ {
+ id=1
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=2
+ connect_to=10
+ connect_to=16
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=3
+ x=1
+ y=5
+ port=title
+ {
+ id=4
+ string_data=Square
+ }
+ port=autoRestoreID
+ {
+ id=5
+ string_data=Square
+ }
+ port=left
+ {
+ id=6
+ connect_to=17
+ }
+ port=right
+ {
+ id=7
+ connect_to=17
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=15
+ x=2
+ y=3
+ port=pos
+ {
+ id=16
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=6
+ connect_to=7
+ }
+}
diff --git a/arts/examples/example_stereobeep.arts b/arts/examples/example_stereobeep.arts
new file mode 100644
index 00000000..69c346e9
--- /dev/null
+++ b/arts/examples/example_stereobeep.arts
@@ -0,0 +1,91 @@
+name=example_stereobeep
+module=Arts::Synth_FREQUENCY
+{
+ id=29
+ x=1
+ y=1
+ port=frequency
+ {
+ id=30
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=31
+ connect_to=36
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=32
+ x=5
+ y=1
+ port=frequency
+ {
+ id=33
+ audio_data=880.00000
+ }
+ port=pos
+ {
+ id=34
+ connect_to=39
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=35
+ x=2
+ y=3
+ port=pos
+ {
+ id=36
+ connect_to=31
+ }
+ port=outvalue
+ {
+ id=37
+ connect_to=44
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=38
+ x=6
+ y=3
+ port=pos
+ {
+ id=39
+ connect_to=34
+ }
+ port=outvalue
+ {
+ id=40
+ connect_to=45
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=41
+ x=2
+ y=5
+ port=title
+ {
+ id=42
+ string_data=StereoBeep
+ }
+ port=autoRestoreID
+ {
+ id=43
+ string_data=StereoBeep
+ }
+ port=left
+ {
+ id=44
+ connect_to=37
+ }
+ port=right
+ {
+ id=45
+ connect_to=40
+ }
+}
diff --git a/arts/examples/example_tremolo.arts b/arts/examples/example_tremolo.arts
new file mode 100644
index 00000000..0a3130f3
--- /dev/null
+++ b/arts/examples/example_tremolo.arts
@@ -0,0 +1,118 @@
+name=example_tremolo
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=0
+ x=1
+ y=1
+ port=busname
+ {
+ id=1
+ string_data=Tremolo
+ }
+ port=left
+ {
+ id=2
+ connect_to=9
+ }
+ port=right
+ {
+ id=3
+ connect_to=13
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=4
+ x=1
+ y=7
+ port=busname
+ {
+ id=5
+ string_data=out_soundcard
+ }
+ port=left
+ {
+ id=6
+ connect_to=11
+ }
+ port=right
+ {
+ id=7
+ connect_to=15
+ }
+}
+module=Arts::Synth_TREMOLO
+{
+ id=8
+ x=1
+ y=5
+ port=invalue
+ {
+ id=9
+ connect_to=2
+ }
+ port=inlfo
+ {
+ id=10
+ connect_to=21
+ }
+ port=outvalue
+ {
+ id=11
+ connect_to=6
+ }
+}
+module=Arts::Synth_TREMOLO
+{
+ id=12
+ x=5
+ y=5
+ port=invalue
+ {
+ id=13
+ connect_to=3
+ }
+ port=inlfo
+ {
+ id=14
+ connect_to=21
+ }
+ port=outvalue
+ {
+ id=15
+ connect_to=7
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=16
+ x=6
+ y=1
+ port=frequency
+ {
+ id=17
+ audio_data=5.00000
+ }
+ port=pos
+ {
+ id=18
+ connect_to=20
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=19
+ x=6
+ y=3
+ port=pos
+ {
+ id=20
+ connect_to=18
+ }
+ port=outvalue
+ {
+ id=21
+ connect_to=10
+ connect_to=14
+ }
+}
diff --git a/arts/examples/example_tri.arts b/arts/examples/example_tri.arts
new file mode 100644
index 00000000..7c9e5673
--- /dev/null
+++ b/arts/examples/example_tri.arts
@@ -0,0 +1,61 @@
+name=example_tri
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=1
+ port=frequency
+ {
+ id=1
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=2
+ connect_to=10
+ connect_to=16
+ }
+}
+module=Arts::Synth_AMAN_PLAY
+{
+ id=3
+ x=1
+ y=5
+ port=title
+ {
+ id=4
+ string_data=Tri
+ }
+ port=autoRestoreID
+ {
+ id=5
+ string_data=Tri
+ }
+ port=left
+ {
+ id=6
+ connect_to=17
+ }
+ port=right
+ {
+ id=7
+ connect_to=17
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=15
+ x=2
+ y=3
+ port=pos
+ {
+ id=16
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=6
+ connect_to=7
+ }
+}
diff --git a/arts/examples/example_xfade.arts b/arts/examples/example_xfade.arts
new file mode 100644
index 00000000..60ed2022
--- /dev/null
+++ b/arts/examples/example_xfade.arts
@@ -0,0 +1,120 @@
+name=example_xfade
+module=Arts::Synth_AMAN_PLAY
+{
+ id=10
+ x=1
+ y=7
+ port=title
+ {
+ id=11
+ string_data=Crossfade
+ }
+ port=autoRestoreID
+ {
+ id=12
+ string_data=Crossfade
+ }
+ port=left
+ {
+ id=13
+ connect_to=48
+ }
+ port=right
+ {
+ id=14
+ connect_to=48
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=15
+ x=1
+ y=3
+ port=pos
+ {
+ id=16
+ connect_to=20
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=33
+ connect_to=45
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=18
+ x=1
+ y=1
+ port=frequency
+ {
+ id=19
+ audio_data=440.00000
+ }
+ port=pos
+ {
+ id=20
+ connect_to=16
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=25
+ x=5
+ y=3
+ port=pos
+ {
+ id=26
+ connect_to=30
+ }
+ port=outvalue
+ {
+ id=27
+ connect_to=37
+ connect_to=46
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=28
+ x=5
+ y=1
+ port=frequency
+ {
+ id=29
+ audio_data=880.00000
+ }
+ port=pos
+ {
+ id=30
+ connect_to=26
+ }
+}
+module=Arts::Synth_XFADE
+{
+ id=44
+ x=3
+ y=5
+ port=invalue1
+ {
+ id=45
+ connect_to=17
+ }
+ port=invalue2
+ {
+ id=46
+ connect_to=27
+ }
+ port=percentage
+ {
+ id=47
+ audio_data=0.00000
+ }
+ port=outvalue
+ {
+ id=48
+ connect_to=13
+ connect_to=14
+ }
+}
diff --git a/arts/examples/instrument_arts_all.arts-map b/arts/examples/instrument_arts_all.arts-map
new file mode 100644
index 00000000..0508f8d8
--- /dev/null
+++ b/arts/examples/instrument_arts_all.arts-map
@@ -0,0 +1,14 @@
+ON program=0 DO structure=instrument_tri.arts
+ON program=1 DO structure=instrument_organ2.arts
+ON program=2 DO structure=instrument_slide1.arts
+ON program=3 DO structure=instrument_square.arts
+ON program=4 DO structure=instrument_neworgan.arts
+ON program=5 DO structure=instrument_nokind.arts
+ON program=6 DO structure=instrument_full_square.arts
+ON program=7 DO structure=instrument_simple_sin.arts
+ON program=8 DO structure=instrument_simple_square.arts
+ON program=9 DO structure=instrument_simple_tri.arts
+ON program=10 DO structure=instrument_slide.arts
+ON program=11 pitch=60 DO structure=instrument_deepdrum.arts
+ON program=11 pitch=61 DO structure=instrument_chirpdrum.arts
+ON program=11 pitch=62 DO structure=instrument_hihat.arts
diff --git a/arts/examples/instrument_chirpdrum.arts b/arts/examples/instrument_chirpdrum.arts
new file mode 100644
index 00000000..8b8dcff7
--- /dev/null
+++ b/arts/examples/instrument_chirpdrum.arts
@@ -0,0 +1,260 @@
+name=instrument_chirpdrum
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=104
+ x=2
+ y=5
+ port=active
+ {
+ id=105
+ connect_to=130
+ }
+ port=invalue
+ {
+ id=106
+ connect_to=116
+ }
+ port=attack
+ {
+ id=107
+ audio_data=0.02000
+ }
+ port=decay
+ {
+ id=108
+ audio_data=0.01000
+ }
+ port=sustain
+ {
+ id=109
+ audio_data=0.00010
+ }
+ port=release
+ {
+ id=110
+ audio_data=0.00100
+ }
+ port=outvalue
+ {
+ id=111
+ connect_to=122
+ }
+ port=done
+ {
+ id=112
+ connect_to=133
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=113
+ x=2
+ y=3
+ port=invalue1
+ {
+ id=114
+ connect_to=118
+ }
+ port=invalue2
+ {
+ id=115
+ connect_to=129
+ }
+ port=outvalue
+ {
+ id=116
+ connect_to=106
+ }
+}
+module=Arts::Synth_NOISE
+{
+ id=117
+ x=1
+ y=2
+ port=outvalue
+ {
+ id=118
+ connect_to=114
+ }
+}
+module=Arts::Synth_MOOG_VCF
+{
+ id=119
+ x=1
+ y=6
+ port=frequency
+ {
+ id=120
+ audio_data=11000.00000
+ }
+ port=resonance
+ {
+ id=121
+ audio_data=1.90000
+ }
+ port=invalue
+ {
+ id=122
+ connect_to=111
+ }
+ port=outvalue
+ {
+ id=123
+ connect_to=126
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=124
+ x=1
+ y=7
+ port=invalue1
+ {
+ id=125
+ audio_data=15.00000
+ }
+ port=invalue2
+ {
+ id=126
+ connect_to=123
+ }
+ port=outvalue
+ {
+ id=127
+ connect_to=142
+ }
+}
+module=Arts::Synth_RC
+{
+ id=139
+ x=1
+ y=10
+ port=b
+ {
+ id=140
+ audio_data=5.00000
+ }
+ port=f
+ {
+ id=141
+ audio_data=5.00000
+ }
+ port=invalue
+ {
+ id=142
+ connect_to=127
+ }
+ port=outvalue
+ {
+ id=143
+ connect_to=132
+ connect_to=131
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=128
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=129
+ connect_to=115
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=130
+ connect_to=105
+ }
+}
+structureport
+{
+ name=left
+ x=2
+ y=13
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=131
+ connect_to=143
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=13
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=132
+ connect_to=143
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=8
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=133
+ connect_to=112
+ }
+}
diff --git a/arts/examples/instrument_deepdrum.arts b/arts/examples/instrument_deepdrum.arts
new file mode 100644
index 00000000..f6b1ebef
--- /dev/null
+++ b/arts/examples/instrument_deepdrum.arts
@@ -0,0 +1,255 @@
+name=instrument_deepdrum
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=144
+ x=2
+ y=5
+ port=active
+ {
+ id=145
+ connect_to=170
+ }
+ port=invalue
+ {
+ id=146
+ connect_to=156
+ }
+ port=attack
+ {
+ id=147
+ audio_data=0.02000
+ }
+ port=decay
+ {
+ id=148
+ audio_data=0.01000
+ }
+ port=sustain
+ {
+ id=149
+ audio_data=0.00100
+ }
+ port=release
+ {
+ id=150
+ audio_data=0.00100
+ }
+ port=outvalue
+ {
+ id=151
+ connect_to=162
+ }
+ port=done
+ {
+ id=152
+ connect_to=173
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=153
+ x=2
+ y=3
+ port=invalue1
+ {
+ id=154
+ connect_to=179
+ }
+ port=invalue2
+ {
+ id=155
+ connect_to=169
+ }
+ port=outvalue
+ {
+ id=156
+ connect_to=146
+ }
+}
+module=Arts::Synth_MOOG_VCF
+{
+ id=159
+ x=1
+ y=6
+ port=frequency
+ {
+ id=160
+ audio_data=400.00000
+ }
+ port=resonance
+ {
+ id=161
+ audio_data=2.90000
+ }
+ port=invalue
+ {
+ id=162
+ connect_to=151
+ }
+ port=outvalue
+ {
+ id=163
+ connect_to=166
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=164
+ x=1
+ y=7
+ port=invalue1
+ {
+ id=165
+ audio_data=150.00000
+ }
+ port=invalue2
+ {
+ id=166
+ connect_to=163
+ }
+ port=outvalue
+ {
+ id=167
+ connect_to=171
+ connect_to=172
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=177
+ x=1
+ y=2
+ port=pos
+ {
+ id=178
+ connect_to=185
+ }
+ port=outvalue
+ {
+ id=179
+ connect_to=154
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=183
+ x=0
+ y=1
+ port=frequency
+ {
+ id=184
+ audio_data=8000.00000
+ }
+ port=pos
+ {
+ id=185
+ connect_to=178
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=168
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=169
+ connect_to=155
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=170
+ connect_to=145
+ }
+}
+structureport
+{
+ name=left
+ x=2
+ y=9
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=171
+ connect_to=167
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=9
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=172
+ connect_to=167
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=8
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=173
+ connect_to=152
+ }
+}
diff --git a/arts/examples/instrument_flexible_slide.arts b/arts/examples/instrument_flexible_slide.arts
new file mode 100644
index 00000000..b1ff28d6
--- /dev/null
+++ b/arts/examples/instrument_flexible_slide.arts
@@ -0,0 +1,537 @@
+name=instrument_flexible_slide
+module=Arts::Synth_FREQUENCY
+{
+ id=4
+ x=4
+ y=3
+ port=frequency
+ {
+ id=5
+ connect_to=79
+ }
+ port=pos
+ {
+ id=6
+ connect_to=32
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=9
+ x=13
+ y=4
+ port=active
+ {
+ id=10
+ connect_to=81
+ }
+ port=invalue
+ {
+ id=11
+ connect_to=29
+ }
+ port=attack
+ {
+ id=12
+ connect_to=78
+ }
+ port=decay
+ {
+ id=13
+ connect_to=76
+ }
+ port=sustain
+ {
+ id=14
+ audio_data=0.70000
+ }
+ port=release
+ {
+ id=15
+ audio_data=0.05000
+ }
+ port=outvalue
+ {
+ id=16
+ connect_to=40
+ }
+ port=done
+ {
+ id=17
+ connect_to=8
+ connect_to=84
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=22
+ x=12
+ y=2
+ port=active
+ {
+ id=23
+ connect_to=81
+ }
+ port=invalue
+ {
+ id=24
+ connect_to=80
+ }
+ port=attack
+ {
+ id=25
+ connect_to=78
+ }
+ port=decay
+ {
+ id=26
+ connect_to=75
+ }
+ port=sustain
+ {
+ id=27
+ audio_data=0.00010
+ }
+ port=release
+ {
+ id=28
+ audio_data=0.10000
+ }
+ port=outvalue
+ {
+ id=29
+ connect_to=11
+ connect_to=43
+ }
+ port=done
+ {
+ id=30
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=31
+ x=5
+ y=4
+ port=pos
+ {
+ id=32
+ connect_to=6
+ }
+ port=outvalue
+ {
+ id=33
+ connect_to=58
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=34
+ x=5
+ y=11
+ port=invalue
+ {
+ id=35
+ connect_to=60
+ }
+ port=frequency
+ {
+ id=36
+ connect_to=72
+ }
+ port=outvalue
+ {
+ id=37
+ connect_to=39
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=38
+ x=6
+ y=12
+ port=invalue1
+ {
+ id=39
+ connect_to=37
+ }
+ port=invalue2
+ {
+ id=40
+ connect_to=16
+ }
+ port=outvalue
+ {
+ id=41
+ connect_to=20
+ connect_to=21
+ connect_to=82
+ connect_to=83
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=42
+ x=11
+ y=6
+ port=invalue1
+ {
+ id=43
+ connect_to=29
+ }
+ port=invalue2
+ {
+ id=44
+ connect_to=74
+ }
+ port=outvalue
+ {
+ id=45
+ connect_to=71
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=46
+ x=1
+ y=3
+ port=invalue1
+ {
+ id=47
+ connect_to=79
+ }
+ port=invalue2
+ {
+ id=48
+ connect_to=73
+ }
+ port=outvalue
+ {
+ id=49
+ connect_to=51
+ connect_to=70
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=50
+ x=2
+ y=5
+ port=frequency
+ {
+ id=51
+ connect_to=49
+ }
+ port=pos
+ {
+ id=52
+ connect_to=54
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=53
+ x=3
+ y=6
+ port=pos
+ {
+ id=54
+ connect_to=52
+ }
+ port=outvalue
+ {
+ id=55
+ connect_to=57
+ }
+}
+module=Arts::Synth_XFADE
+{
+ id=56
+ x=4
+ y=7
+ port=invalue1
+ {
+ id=57
+ connect_to=55
+ }
+ port=invalue2
+ {
+ id=58
+ connect_to=33
+ }
+ port=percentage
+ {
+ id=59
+ connect_to=68
+ }
+ port=outvalue
+ {
+ id=60
+ connect_to=35
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=61
+ x=7
+ y=3
+ port=invalue1
+ {
+ id=62
+ connect_to=80
+ }
+ port=invalue2
+ {
+ id=63
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=64
+ connect_to=66
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=65
+ x=8
+ y=4
+ port=invalue1
+ {
+ id=66
+ connect_to=64
+ }
+ port=invalue2
+ {
+ id=67
+ audio_data=-1.00000
+ }
+ port=outvalue
+ {
+ id=68
+ connect_to=59
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=69
+ x=7
+ y=9
+ port=invalue1
+ {
+ id=70
+ connect_to=49
+ }
+ port=invalue2
+ {
+ id=71
+ connect_to=45
+ }
+ port=outvalue
+ {
+ id=72
+ connect_to=36
+ }
+}
+structureport
+{
+ name=detune
+ x=1
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=73
+ connect_to=48
+ }
+}
+structureport
+{
+ name=cutoff
+ x=13
+ y=5
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=74
+ connect_to=44
+ }
+}
+structureport
+{
+ name=decay
+ x=16
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=75
+ connect_to=26
+ }
+}
+structureport
+{
+ name=decay2
+ x=19
+ y=0
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=76
+ connect_to=13
+ }
+}
+structureport
+{
+ name=attack
+ x=17
+ y=0
+ position=5
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=78
+ connect_to=12
+ connect_to=25
+ }
+}
+structureport
+{
+ name=frequency
+ x=3
+ y=0
+ position=6
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=79
+ connect_to=5
+ connect_to=47
+ }
+}
+structureport
+{
+ name=velocity
+ x=5
+ y=0
+ position=7
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=80
+ connect_to=62
+ connect_to=24
+ }
+}
+structureport
+{
+ name=pressed
+ x=7
+ y=0
+ position=8
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=81
+ connect_to=23
+ connect_to=10
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=14
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=82
+ connect_to=41
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=14
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=83
+ connect_to=41
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=14
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=84
+ connect_to=17
+ }
+}
diff --git a/arts/examples/instrument_flexible_slide_GUI.arts b/arts/examples/instrument_flexible_slide_GUI.arts
new file mode 100644
index 00000000..3b0f0bca
--- /dev/null
+++ b/arts/examples/instrument_flexible_slide_GUI.arts
@@ -0,0 +1,481 @@
+name=instrument_flexible_slide_GUI
+module=Arts::Poti
+{
+ id=0
+ x=3
+ y=4
+ port=widgetID
+ {
+ id=1
+ }
+ port=parent
+ {
+ id=2
+ }
+ port=x
+ {
+ id=3
+ any_data=value:000000056c6f6e67000000000400000064
+ }
+ port=y
+ {
+ id=4
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=5
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=height
+ {
+ id=6
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=visible
+ {
+ id=7
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=8
+ string_data=DETUNE
+ }
+ port=color
+ {
+ id=9
+ string_data=#ff8000
+ }
+ port=min
+ {
+ id=10
+ audio_data=2.00000
+ }
+ port=max
+ {
+ id=11
+ audio_data=2.03000
+ }
+ port=value
+ {
+ id=12
+ }
+}
+module=Arts::Widget
+{
+ id=13
+ x=1
+ y=2
+ port=widgetID
+ {
+ id=14
+ }
+ port=parent
+ {
+ id=15
+ }
+ port=x
+ {
+ id=16
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=y
+ {
+ id=17
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=18
+ any_data=value:000000056c6f6e67000000000400000032
+ }
+ port=height
+ {
+ id=19
+ any_data=value:000000056c6f6e67000000000400000032
+ }
+ port=visible
+ {
+ id=20
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+}
+module=Arts::Poti
+{
+ id=21
+ x=3
+ y=6
+ port=widgetID
+ {
+ id=22
+ }
+ port=parent
+ {
+ id=23
+ }
+ port=x
+ {
+ id=24
+ any_data=value:000000056c6f6e670000000004000000c8
+ }
+ port=y
+ {
+ id=25
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=26
+ }
+ port=height
+ {
+ id=27
+ }
+ port=visible
+ {
+ id=28
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=29
+ string_data=CUTOFF
+ }
+ port=color
+ {
+ id=30
+ string_data=red
+ }
+ port=min
+ {
+ id=31
+ }
+ port=max
+ {
+ id=32
+ }
+ port=value
+ {
+ id=33
+ }
+}
+module=Arts::Poti
+{
+ id=34
+ x=3
+ y=10
+ port=widgetID
+ {
+ id=35
+ }
+ port=parent
+ {
+ id=36
+ }
+ port=x
+ {
+ id=37
+ any_data=value:000000056c6f6e67000000000400000190
+ }
+ port=y
+ {
+ id=38
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=39
+ }
+ port=height
+ {
+ id=40
+ }
+ port=visible
+ {
+ id=41
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=42
+ string_data=DECAY
+ }
+ port=color
+ {
+ id=43
+ string_data=#00A000
+ }
+ port=min
+ {
+ id=44
+ audio_data=0.01000
+ }
+ port=max
+ {
+ id=45
+ audio_data=8.00000
+ }
+ port=value
+ {
+ id=46
+ }
+}
+module=Arts::Poti
+{
+ id=47
+ x=3
+ y=12
+ port=widgetID
+ {
+ id=48
+ }
+ port=parent
+ {
+ id=49
+ }
+ port=x
+ {
+ id=50
+ any_data=value:000000056c6f6e670000000004000001f4
+ }
+ port=y
+ {
+ id=51
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=52
+ }
+ port=height
+ {
+ id=53
+ }
+ port=visible
+ {
+ id=54
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=55
+ string_data=DECAY2
+ }
+ port=color
+ {
+ id=56
+ string_data=darkgrey
+ }
+ port=min
+ {
+ id=57
+ audio_data=0.00010
+ }
+ port=max
+ {
+ id=58
+ audio_data=2.00000
+ }
+ port=value
+ {
+ id=59
+ }
+}
+module=Arts::Poti
+{
+ id=60
+ x=3
+ y=8
+ port=widgetID
+ {
+ id=61
+ }
+ port=parent
+ {
+ id=62
+ }
+ port=x
+ {
+ id=63
+ any_data=value:000000056c6f6e6700000000040000012c
+ }
+ port=y
+ {
+ id=64
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=65
+ }
+ port=height
+ {
+ id=66
+ }
+ port=visible
+ {
+ id=67
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=68
+ string_data=ATTACK
+ }
+ port=color
+ {
+ id=69
+ string_data=#00A000
+ }
+ port=min
+ {
+ id=70
+ audio_data=0.01000
+ }
+ port=max
+ {
+ id=71
+ audio_data=0.90000
+ }
+ port=value
+ {
+ id=72
+ }
+}
+structureport
+{
+ name=parent
+ x=2
+ y=1
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=73
+ }
+}
+structureport
+{
+ name=x
+ x=3
+ y=1
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=property
+ }
+ data
+ {
+ id=74
+ }
+}
+structureport
+{
+ name=y
+ x=4
+ y=1
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=property
+ }
+ data
+ {
+ id=75
+ }
+}
+structureport
+{
+ name=detune
+ x=5
+ y=5
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=76
+ }
+}
+structureport
+{
+ name=cutoff
+ x=5
+ y=7
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=77
+ }
+}
+structureport
+{
+ name=decay
+ x=5
+ y=11
+ position=3
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=78
+ }
+}
+structureport
+{
+ name=decay2
+ x=5
+ y=13
+ position=4
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=79
+ }
+}
+structureport
+{
+ name=attack
+ x=5
+ y=9
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=80
+ }
+}
diff --git a/arts/examples/instrument_fm_horn.arts b/arts/examples/instrument_fm_horn.arts
new file mode 100644
index 00000000..698c7792
--- /dev/null
+++ b/arts/examples/instrument_fm_horn.arts
@@ -0,0 +1,301 @@
+name=instrument_fm_horn
+module=Arts::Synth_FM_SOURCE
+{
+ id=0
+ x=2
+ y=7
+ port=frequency
+ {
+ id=1
+ connect_to=47
+ }
+ port=modulator
+ {
+ id=2
+ connect_to=22
+ }
+ port=modlevel
+ {
+ id=3
+ audio_data=0.30000
+ }
+ port=pos
+ {
+ id=4
+ connect_to=6
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=5
+ x=3
+ y=8
+ port=pos
+ {
+ id=6
+ connect_to=4
+ }
+ port=outvalue
+ {
+ id=7
+ connect_to=16
+ connect_to=33
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=8
+ x=2
+ y=4
+ port=frequency
+ {
+ id=9
+ connect_to=45
+ }
+ port=pos
+ {
+ id=10
+ connect_to=12
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=11
+ x=3
+ y=5
+ port=pos
+ {
+ id=12
+ connect_to=10
+ }
+ port=outvalue
+ {
+ id=13
+ connect_to=19
+ }
+}
+module=Arts::Synth_CDELAY
+{
+ id=14
+ x=7
+ y=8
+ port=time
+ {
+ id=15
+ }
+ port=invalue
+ {
+ id=16
+ connect_to=7
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=20
+ }
+}
+module=Arts::Synth_XFADE
+{
+ id=18
+ x=7
+ y=6
+ port=invalue1
+ {
+ id=19
+ connect_to=13
+ }
+ port=invalue2
+ {
+ id=20
+ connect_to=17
+ }
+ port=percentage
+ {
+ id=21
+ audio_data=0.40000
+ }
+ port=outvalue
+ {
+ id=22
+ connect_to=2
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=31
+ x=3
+ y=11
+ port=active
+ {
+ id=32
+ connect_to=49
+ }
+ port=invalue
+ {
+ id=33
+ connect_to=7
+ }
+ port=attack
+ {
+ id=34
+ audio_data=0.10000
+ }
+ port=decay
+ {
+ id=35
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=36
+ audio_data=0.70000
+ }
+ port=release
+ {
+ id=37
+ audio_data=0.10000
+ }
+ port=outvalue
+ {
+ id=38
+ connect_to=29
+ connect_to=30
+ connect_to=50
+ connect_to=51
+ }
+ port=done
+ {
+ id=39
+ connect_to=41
+ connect_to=52
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=42
+ x=1
+ y=3
+ port=invalue1
+ {
+ id=43
+ connect_to=47
+ }
+ port=invalue2
+ {
+ id=44
+ audio_data=1.01000
+ }
+ port=outvalue
+ {
+ id=45
+ connect_to=9
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=47
+ connect_to=43
+ connect_to=1
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=48
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=49
+ connect_to=32
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=13
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=50
+ connect_to=38
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=13
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=51
+ connect_to=38
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=13
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=52
+ connect_to=39
+ }
+}
diff --git a/arts/examples/instrument_full_square.arts b/arts/examples/instrument_full_square.arts
new file mode 100644
index 00000000..2e562000
--- /dev/null
+++ b/arts/examples/instrument_full_square.arts
@@ -0,0 +1,422 @@
+name=instrument_full_square
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=2
+ port=frequency
+ {
+ id=1
+ connect_to=59
+ }
+ port=pos
+ {
+ id=2
+ connect_to=13
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=3
+ x=0
+ y=9
+ port=active
+ {
+ id=4
+ connect_to=61
+ }
+ port=invalue
+ {
+ id=5
+ connect_to=58
+ }
+ port=attack
+ {
+ id=6
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=7
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=8
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=9
+ audio_data=0.30000
+ }
+ port=outvalue
+ {
+ id=10
+ connect_to=62
+ connect_to=63
+ }
+ port=done
+ {
+ id=11
+ connect_to=64
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=12
+ x=1
+ y=4
+ port=pos
+ {
+ id=13
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=16
+ connect_to=21
+ connect_to=28
+ connect_to=52
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=15
+ x=6
+ y=6
+ port=invalue1
+ {
+ id=16
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=17
+ connect_to=38
+ }
+ port=outvalue
+ {
+ id=18
+ connect_to=24
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=19
+ x=15
+ y=6
+ port=invalue1
+ {
+ id=20
+ connect_to=26
+ }
+ port=invalue2
+ {
+ id=21
+ connect_to=14
+ }
+ port=outvalue
+ {
+ id=22
+ connect_to=48
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=23
+ x=10
+ y=6
+ port=invalue1
+ {
+ id=24
+ connect_to=18
+ }
+ port=invalue2
+ {
+ id=25
+ connect_to=42
+ }
+ port=outvalue
+ {
+ id=26
+ connect_to=20
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=27
+ x=6
+ y=2
+ port=invalue1
+ {
+ id=28
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=29
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=30
+ connect_to=32
+ connect_to=36
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=31
+ x=10
+ y=2
+ port=invalue1
+ {
+ id=32
+ connect_to=30
+ }
+ port=invalue2
+ {
+ id=33
+ audio_data=16.00000
+ }
+ port=outvalue
+ {
+ id=34
+ connect_to=40
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=35
+ x=6
+ y=4
+ port=invalue
+ {
+ id=36
+ connect_to=30
+ }
+ port=frequency
+ {
+ id=37
+ audio_data=6000.00000
+ }
+ port=outvalue
+ {
+ id=38
+ connect_to=17
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=39
+ x=10
+ y=4
+ port=invalue
+ {
+ id=40
+ connect_to=34
+ }
+ port=frequency
+ {
+ id=41
+ audio_data=2000.00000
+ }
+ port=outvalue
+ {
+ id=42
+ connect_to=25
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=43
+ x=12
+ y=9
+ port=invalue
+ {
+ id=44
+ connect_to=54
+ }
+ port=frequency
+ {
+ id=45
+ audio_data=8000.00000
+ }
+ port=outvalue
+ {
+ id=46
+ connect_to=57
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=47
+ x=16
+ y=7
+ port=invalue1
+ {
+ id=48
+ connect_to=22
+ }
+ port=invalue2
+ {
+ id=49
+ audio_data=0.10000
+ }
+ port=outvalue
+ {
+ id=50
+ connect_to=53
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=51
+ x=16
+ y=9
+ port=invalue1
+ {
+ id=52
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=53
+ connect_to=50
+ }
+ port=outvalue
+ {
+ id=54
+ connect_to=44
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=55
+ x=8
+ y=9
+ port=invalue1
+ {
+ id=56
+ audio_data=0.20000
+ }
+ port=invalue2
+ {
+ id=57
+ connect_to=46
+ }
+ port=outvalue
+ {
+ id=58
+ connect_to=5
+ }
+}
+structureport
+{
+ name=frequency
+ x=2
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=59
+ connect_to=1
+ }
+}
+structureport
+{
+ name=velocity
+ x=4
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=60
+ }
+}
+structureport
+{
+ name=pressed
+ x=1
+ y=8
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=61
+ connect_to=4
+ }
+}
+structureport
+{
+ name=left
+ x=2
+ y=11
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=62
+ connect_to=10
+ }
+}
+structureport
+{
+ name=right
+ x=4
+ y=11
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=63
+ connect_to=10
+ }
+}
+structureport
+{
+ name=done
+ x=6
+ y=11
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=64
+ connect_to=11
+ }
+}
diff --git a/arts/examples/instrument_hihat.arts b/arts/examples/instrument_hihat.arts
new file mode 100644
index 00000000..68205093
--- /dev/null
+++ b/arts/examples/instrument_hihat.arts
@@ -0,0 +1,235 @@
+name=instrument_hihat
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=0
+ x=2
+ y=5
+ port=active
+ {
+ id=1
+ connect_to=31
+ }
+ port=invalue
+ {
+ id=2
+ connect_to=12
+ }
+ port=attack
+ {
+ id=3
+ audio_data=0.00010
+ }
+ port=decay
+ {
+ id=4
+ audio_data=0.04000
+ }
+ port=sustain
+ {
+ id=5
+ audio_data=0.00010
+ }
+ port=release
+ {
+ id=6
+ audio_data=0.00100
+ }
+ port=outvalue
+ {
+ id=7
+ connect_to=18
+ connect_to=22
+ }
+ port=done
+ {
+ id=8
+ connect_to=34
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=9
+ x=2
+ y=3
+ port=invalue1
+ {
+ id=10
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=11
+ connect_to=30
+ }
+ port=outvalue
+ {
+ id=12
+ connect_to=2
+ }
+}
+module=Arts::Synth_NOISE
+{
+ id=13
+ x=1
+ y=2
+ port=outvalue
+ {
+ id=14
+ connect_to=10
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=20
+ x=1
+ y=7
+ port=invalue1
+ {
+ id=21
+ audio_data=2.00000
+ }
+ port=invalue2
+ {
+ id=22
+ connect_to=7
+ }
+ port=outvalue
+ {
+ id=23
+ connect_to=27
+ }
+}
+module=Arts::Synth_RC
+{
+ id=24
+ x=1
+ y=10
+ port=b
+ {
+ id=25
+ audio_data=2.00000
+ }
+ port=f
+ {
+ id=26
+ audio_data=4.00000
+ }
+ port=invalue
+ {
+ id=27
+ connect_to=23
+ }
+ port=outvalue
+ {
+ id=28
+ connect_to=32
+ connect_to=33
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=29
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=30
+ connect_to=11
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=31
+ connect_to=1
+ }
+}
+structureport
+{
+ name=left
+ x=2
+ y=13
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=32
+ connect_to=28
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=13
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=33
+ connect_to=28
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=8
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=34
+ connect_to=8
+ }
+}
diff --git a/arts/examples/instrument_moog_vcf_tune.arts b/arts/examples/instrument_moog_vcf_tune.arts
new file mode 100644
index 00000000..51d057a7
--- /dev/null
+++ b/arts/examples/instrument_moog_vcf_tune.arts
@@ -0,0 +1,341 @@
+name=instrument_moog_vcf_tune
+module=Arts::Synth_FREQUENCY
+{
+ id=4
+ x=0
+ y=5
+ port=frequency
+ {
+ id=5
+ connect_to=48
+ }
+ port=pos
+ {
+ id=6
+ connect_to=23
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=7
+ x=5
+ y=13
+ port=active
+ {
+ id=8
+ connect_to=50
+ }
+ port=invalue
+ {
+ id=9
+ connect_to=43
+ }
+ port=attack
+ {
+ id=10
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=11
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=12
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=13
+ audio_data=0.20000
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=20
+ connect_to=21
+ connect_to=51
+ connect_to=52
+ }
+ port=done
+ {
+ id=15
+ connect_to=17
+ connect_to=53
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=22
+ x=1
+ y=6
+ port=pos
+ {
+ id=23
+ connect_to=6
+ }
+ port=outvalue
+ {
+ id=24
+ connect_to=32
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=25
+ x=5
+ y=7
+ port=pos
+ {
+ id=26
+ connect_to=30
+ }
+ port=outvalue
+ {
+ id=27
+ connect_to=33
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=28
+ x=4
+ y=6
+ port=frequency
+ {
+ id=29
+ connect_to=38
+ }
+ port=pos
+ {
+ id=30
+ connect_to=26
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=31
+ x=3
+ y=9
+ port=invalue1
+ {
+ id=32
+ connect_to=24
+ }
+ port=invalue2
+ {
+ id=33
+ connect_to=27
+ }
+ port=outvalue
+ {
+ id=34
+ connect_to=42
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=35
+ x=3
+ y=5
+ port=invalue1
+ {
+ id=36
+ connect_to=48
+ }
+ port=invalue2
+ {
+ id=37
+ connect_to=47
+ }
+ port=outvalue
+ {
+ id=38
+ connect_to=29
+ }
+}
+module=Arts::Synth_MOOG_VCF
+{
+ id=39
+ x=7
+ y=11
+ port=frequency
+ {
+ id=40
+ }
+ port=resonance
+ {
+ id=41
+ }
+ port=invalue
+ {
+ id=42
+ connect_to=34
+ }
+ port=outvalue
+ {
+ id=43
+ connect_to=9
+ }
+}
+structureport
+{
+ name=cutoff
+ x=9
+ y=10
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=45
+ }
+}
+structureport
+{
+ name=resonance
+ x=10
+ y=10
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=46
+ }
+}
+structureport
+{
+ name=detune
+ x=5
+ y=4
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=47
+ connect_to=37
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=4
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=48
+ connect_to=5
+ connect_to=36
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=5
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=49
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=6
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=50
+ connect_to=8
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=15
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=51
+ connect_to=14
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=15
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=52
+ connect_to=14
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=15
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=53
+ connect_to=15
+ }
+}
diff --git a/arts/examples/instrument_moog_vcf_tune_GUI.arts b/arts/examples/instrument_moog_vcf_tune_GUI.arts
new file mode 100644
index 00000000..6db62f60
--- /dev/null
+++ b/arts/examples/instrument_moog_vcf_tune_GUI.arts
@@ -0,0 +1,331 @@
+name=instrument_moog_vcf_tune_GUI
+module=Arts::Widget
+{
+ id=0
+ x=1
+ y=2
+ port=widgetID
+ {
+ id=1
+ }
+ port=parent
+ {
+ id=2
+ }
+ port=x
+ {
+ id=3
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=y
+ {
+ id=4
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=5
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=height
+ {
+ id=6
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=visible
+ {
+ id=7
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+}
+module=Arts::Poti
+{
+ id=8
+ x=3
+ y=4
+ port=widgetID
+ {
+ id=9
+ }
+ port=parent
+ {
+ id=10
+ }
+ port=x
+ {
+ id=11
+ any_data=value:000000056c6f6e67000000000400000064
+ }
+ port=y
+ {
+ id=12
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=13
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=height
+ {
+ id=14
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=visible
+ {
+ id=15
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=16
+ string_data= CUTOFF
+ }
+ port=color
+ {
+ id=17
+ string_data=red
+ }
+ port=min
+ {
+ id=18
+ audio_data=100.00000
+ }
+ port=max
+ {
+ id=19
+ audio_data=8000.00000
+ }
+ port=value
+ {
+ id=20
+ }
+}
+module=Arts::Poti
+{
+ id=21
+ x=3
+ y=7
+ port=widgetID
+ {
+ id=22
+ }
+ port=parent
+ {
+ id=23
+ }
+ port=x
+ {
+ id=24
+ any_data=value:000000056c6f6e670000000004000000c8
+ }
+ port=y
+ {
+ id=25
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=26
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=height
+ {
+ id=27
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=visible
+ {
+ id=28
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=29
+ string_data= RESO
+ }
+ port=color
+ {
+ id=30
+ string_data=red
+ }
+ port=min
+ {
+ id=31
+ audio_data=0.00000
+ }
+ port=max
+ {
+ id=32
+ audio_data=3.95000
+ }
+ port=value
+ {
+ id=33
+ }
+}
+module=Arts::Poti
+{
+ id=34
+ x=3
+ y=10
+ port=widgetID
+ {
+ id=35
+ }
+ port=parent
+ {
+ id=36
+ }
+ port=x
+ {
+ id=37
+ any_data=value:000000056c6f6e6700000000040000012c
+ }
+ port=y
+ {
+ id=38
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=39
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=height
+ {
+ id=40
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=visible
+ {
+ id=41
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=42
+ string_data=DETUNE
+ }
+ port=color
+ {
+ id=43
+ string_data=orange
+ }
+ port=min
+ {
+ id=44
+ audio_data=1.00000
+ }
+ port=max
+ {
+ id=45
+ audio_data=1.02000
+ }
+ port=value
+ {
+ id=46
+ }
+}
+structureport
+{
+ name=parent
+ x=2
+ y=1
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=47
+ }
+}
+structureport
+{
+ name=x
+ x=3
+ y=1
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=property
+ }
+ data
+ {
+ id=48
+ }
+}
+structureport
+{
+ name=y
+ x=4
+ y=1
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=property
+ }
+ data
+ {
+ id=49
+ }
+}
+structureport
+{
+ name=cutoff
+ x=5
+ y=5
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=50
+ }
+}
+structureport
+{
+ name=resonance
+ x=5
+ y=8
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=51
+ }
+}
+structureport
+{
+ name=detune
+ x=5
+ y=11
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=52
+ }
+}
diff --git a/arts/examples/instrument_neworgan.arts b/arts/examples/instrument_neworgan.arts
new file mode 100644
index 00000000..7bdbc316
--- /dev/null
+++ b/arts/examples/instrument_neworgan.arts
@@ -0,0 +1,532 @@
+name=instrument_neworgan
+module=Arts::Synth_FREQUENCY
+{
+ id=4
+ x=1
+ y=4
+ port=frequency
+ {
+ id=5
+ connect_to=93
+ }
+ port=pos
+ {
+ id=6
+ connect_to=23
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=7
+ x=3
+ y=14
+ port=active
+ {
+ id=8
+ connect_to=95
+ }
+ port=invalue
+ {
+ id=9
+ connect_to=70
+ }
+ port=attack
+ {
+ id=10
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=11
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=12
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=13
+ audio_data=0.30000
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=20
+ connect_to=21
+ connect_to=90
+ connect_to=91
+ }
+ port=done
+ {
+ id=15
+ connect_to=17
+ connect_to=92
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=22
+ x=1
+ y=6
+ port=pos
+ {
+ id=23
+ connect_to=6
+ }
+ port=outvalue
+ {
+ id=24
+ connect_to=64
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=25
+ x=5
+ y=2
+ port=invalue1
+ {
+ id=26
+ connect_to=93
+ }
+ port=invalue2
+ {
+ id=27
+ audio_data=1.00000
+ }
+ port=outvalue
+ {
+ id=28
+ connect_to=47
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=29
+ x=5
+ y=6
+ port=pos
+ {
+ id=30
+ connect_to=48
+ }
+ port=outvalue
+ {
+ id=31
+ connect_to=65
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=32
+ x=9
+ y=2
+ port=invalue1
+ {
+ id=33
+ connect_to=93
+ }
+ port=invalue2
+ {
+ id=34
+ audio_data=8.00000
+ }
+ port=outvalue
+ {
+ id=35
+ connect_to=50
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=36
+ x=9
+ y=6
+ port=pos
+ {
+ id=37
+ connect_to=51
+ }
+ port=outvalue
+ {
+ id=38
+ connect_to=57
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=39
+ x=13
+ y=6
+ port=pos
+ {
+ id=40
+ connect_to=54
+ }
+ port=outvalue
+ {
+ id=41
+ connect_to=61
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=42
+ x=13
+ y=2
+ port=invalue1
+ {
+ id=43
+ connect_to=93
+ }
+ port=invalue2
+ {
+ id=44
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=45
+ connect_to=53
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=46
+ x=5
+ y=4
+ port=frequency
+ {
+ id=47
+ connect_to=28
+ }
+ port=pos
+ {
+ id=48
+ connect_to=30
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=49
+ x=9
+ y=4
+ port=frequency
+ {
+ id=50
+ connect_to=35
+ }
+ port=pos
+ {
+ id=51
+ connect_to=37
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=52
+ x=13
+ y=4
+ port=frequency
+ {
+ id=53
+ connect_to=45
+ }
+ port=pos
+ {
+ id=54
+ connect_to=40
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=55
+ x=5
+ y=10
+ port=invalue1
+ {
+ id=56
+ connect_to=66
+ }
+ port=invalue2
+ {
+ id=57
+ connect_to=38
+ }
+ port=outvalue
+ {
+ id=58
+ connect_to=60
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=59
+ x=9
+ y=11
+ port=invalue1
+ {
+ id=60
+ connect_to=58
+ }
+ port=invalue2
+ {
+ id=61
+ connect_to=41
+ }
+ port=outvalue
+ {
+ id=62
+ connect_to=86
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=63
+ x=1
+ y=9
+ port=invalue1
+ {
+ id=64
+ connect_to=24
+ }
+ port=invalue2
+ {
+ id=65
+ connect_to=31
+ }
+ port=outvalue
+ {
+ id=66
+ connect_to=56
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=67
+ x=13
+ y=13
+ port=invalue1
+ {
+ id=68
+ connect_to=74
+ }
+ port=invalue2
+ {
+ id=69
+ audio_data=0.20000
+ }
+ port=outvalue
+ {
+ id=70
+ connect_to=9
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=71
+ x=13
+ y=11
+ port=invalue
+ {
+ id=72
+ connect_to=88
+ }
+ port=frequency
+ {
+ id=73
+ audio_data=5000.00000
+ }
+ port=outvalue
+ {
+ id=74
+ connect_to=68
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=75
+ x=17
+ y=2
+ port=invalue1
+ {
+ id=76
+ connect_to=93
+ }
+ port=invalue2
+ {
+ id=77
+ audio_data=4.00000
+ }
+ port=outvalue
+ {
+ id=78
+ connect_to=80
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=79
+ x=17
+ y=4
+ port=frequency
+ {
+ id=80
+ connect_to=78
+ }
+ port=pos
+ {
+ id=81
+ connect_to=83
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=82
+ x=17
+ y=6
+ port=pos
+ {
+ id=83
+ connect_to=81
+ }
+ port=outvalue
+ {
+ id=84
+ connect_to=87
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=85
+ x=17
+ y=9
+ port=invalue1
+ {
+ id=86
+ connect_to=62
+ }
+ port=invalue2
+ {
+ id=87
+ connect_to=84
+ }
+ port=outvalue
+ {
+ id=88
+ connect_to=72
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=16
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=90
+ connect_to=14
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=16
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=91
+ connect_to=14
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=16
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=92
+ connect_to=15
+ }
+}
+structureport
+{
+ name=frequency
+ x=2
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=93
+ connect_to=5
+ connect_to=26
+ connect_to=33
+ connect_to=43
+ connect_to=76
+ }
+}
+structureport
+{
+ name=velocity
+ x=4
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=94
+ }
+}
+structureport
+{
+ name=pressed
+ x=6
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=95
+ connect_to=8
+ }
+}
diff --git a/arts/examples/instrument_nokind.arts b/arts/examples/instrument_nokind.arts
new file mode 100644
index 00000000..d0c78585
--- /dev/null
+++ b/arts/examples/instrument_nokind.arts
@@ -0,0 +1,503 @@
+name=instrument_nokind
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=2
+ port=frequency
+ {
+ id=1
+ connect_to=77
+ }
+ port=pos
+ {
+ id=2
+ connect_to=13
+ connect_to=64
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=3
+ x=3
+ y=9
+ port=active
+ {
+ id=4
+ connect_to=79
+ }
+ port=invalue
+ {
+ id=5
+ connect_to=73
+ }
+ port=attack
+ {
+ id=6
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=7
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=8
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=9
+ audio_data=0.30000
+ }
+ port=outvalue
+ {
+ id=10
+ connect_to=74
+ connect_to=75
+ }
+ port=done
+ {
+ id=11
+ connect_to=76
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=12
+ x=1
+ y=4
+ port=pos
+ {
+ id=13
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=16
+ connect_to=21
+ connect_to=28
+ connect_to=52
+ connect_to=56
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=15
+ x=6
+ y=6
+ port=invalue1
+ {
+ id=16
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=17
+ connect_to=38
+ }
+ port=outvalue
+ {
+ id=18
+ connect_to=24
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=19
+ x=14
+ y=6
+ port=invalue1
+ {
+ id=20
+ connect_to=26
+ }
+ port=invalue2
+ {
+ id=21
+ connect_to=14
+ }
+ port=outvalue
+ {
+ id=22
+ connect_to=48
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=23
+ x=10
+ y=6
+ port=invalue1
+ {
+ id=24
+ connect_to=18
+ }
+ port=invalue2
+ {
+ id=25
+ connect_to=42
+ }
+ port=outvalue
+ {
+ id=26
+ connect_to=20
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=27
+ x=6
+ y=2
+ port=invalue1
+ {
+ id=28
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=29
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=30
+ connect_to=32
+ connect_to=36
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=31
+ x=10
+ y=2
+ port=invalue1
+ {
+ id=32
+ connect_to=30
+ }
+ port=invalue2
+ {
+ id=33
+ audio_data=16.00000
+ }
+ port=outvalue
+ {
+ id=34
+ connect_to=40
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=35
+ x=6
+ y=4
+ port=invalue
+ {
+ id=36
+ connect_to=30
+ }
+ port=frequency
+ {
+ id=37
+ audio_data=6000.00000
+ }
+ port=outvalue
+ {
+ id=38
+ connect_to=17
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=39
+ x=10
+ y=4
+ port=invalue
+ {
+ id=40
+ connect_to=34
+ }
+ port=frequency
+ {
+ id=41
+ audio_data=7000.00000
+ }
+ port=outvalue
+ {
+ id=42
+ connect_to=25
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=43
+ x=15
+ y=11
+ port=invalue
+ {
+ id=44
+ connect_to=54
+ }
+ port=frequency
+ {
+ id=45
+ audio_data=8000.00000
+ }
+ port=outvalue
+ {
+ id=46
+ connect_to=60
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=47
+ x=15
+ y=7
+ port=invalue1
+ {
+ id=48
+ connect_to=22
+ }
+ port=invalue2
+ {
+ id=49
+ audio_data=0.10000
+ }
+ port=outvalue
+ {
+ id=50
+ connect_to=53
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=51
+ x=15
+ y=9
+ port=invalue1
+ {
+ id=52
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=53
+ connect_to=50
+ }
+ port=outvalue
+ {
+ id=54
+ connect_to=44
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=55
+ x=11
+ y=13
+ port=invalue1
+ {
+ id=56
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=57
+ connect_to=62
+ }
+ port=outvalue
+ {
+ id=58
+ connect_to=68
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=59
+ x=15
+ y=13
+ port=invalue1
+ {
+ id=60
+ connect_to=46
+ }
+ port=invalue2
+ {
+ id=61
+ audio_data=0.50000
+ }
+ port=outvalue
+ {
+ id=62
+ connect_to=57
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=63
+ x=1
+ y=7
+ port=pos
+ {
+ id=64
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=65
+ connect_to=67
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=66
+ x=11
+ y=11
+ port=invalue1
+ {
+ id=67
+ connect_to=65
+ }
+ port=invalue2
+ {
+ id=68
+ connect_to=58
+ }
+ port=outvalue
+ {
+ id=69
+ connect_to=71
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=70
+ x=11
+ y=9
+ port=invalue1
+ {
+ id=71
+ connect_to=69
+ }
+ port=invalue2
+ {
+ id=72
+ audio_data=0.25000
+ }
+ port=outvalue
+ {
+ id=73
+ connect_to=5
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=13
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=74
+ connect_to=10
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=13
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=75
+ connect_to=10
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=13
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=76
+ connect_to=11
+ }
+}
+structureport
+{
+ name=frequency
+ x=2
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=77
+ connect_to=1
+ }
+}
+structureport
+{
+ name=velocity
+ x=4
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=78
+ }
+}
+structureport
+{
+ name=pressed
+ x=6
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=79
+ connect_to=4
+ }
+}
diff --git a/arts/examples/instrument_organ2.arts b/arts/examples/instrument_organ2.arts
new file mode 100644
index 00000000..85fb1271
--- /dev/null
+++ b/arts/examples/instrument_organ2.arts
@@ -0,0 +1,532 @@
+name=instrument_organ2
+module=Arts::Synth_FREQUENCY
+{
+ id=4
+ x=1
+ y=4
+ port=frequency
+ {
+ id=5
+ connect_to=93
+ }
+ port=pos
+ {
+ id=6
+ connect_to=23
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=7
+ x=3
+ y=14
+ port=active
+ {
+ id=8
+ connect_to=95
+ }
+ port=invalue
+ {
+ id=9
+ connect_to=70
+ }
+ port=attack
+ {
+ id=10
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=11
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=12
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=13
+ audio_data=0.30000
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=20
+ connect_to=21
+ connect_to=90
+ connect_to=91
+ }
+ port=done
+ {
+ id=15
+ connect_to=17
+ connect_to=92
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=22
+ x=1
+ y=6
+ port=pos
+ {
+ id=23
+ connect_to=6
+ }
+ port=outvalue
+ {
+ id=24
+ connect_to=64
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=25
+ x=5
+ y=2
+ port=invalue1
+ {
+ id=26
+ connect_to=93
+ }
+ port=invalue2
+ {
+ id=27
+ audio_data=1.00000
+ }
+ port=outvalue
+ {
+ id=28
+ connect_to=47
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=29
+ x=5
+ y=6
+ port=pos
+ {
+ id=30
+ connect_to=48
+ }
+ port=outvalue
+ {
+ id=31
+ connect_to=65
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=32
+ x=9
+ y=2
+ port=invalue1
+ {
+ id=33
+ connect_to=93
+ }
+ port=invalue2
+ {
+ id=34
+ audio_data=8.00000
+ }
+ port=outvalue
+ {
+ id=35
+ connect_to=50
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=36
+ x=9
+ y=6
+ port=pos
+ {
+ id=37
+ connect_to=51
+ }
+ port=outvalue
+ {
+ id=38
+ connect_to=57
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=39
+ x=13
+ y=6
+ port=pos
+ {
+ id=40
+ connect_to=54
+ }
+ port=outvalue
+ {
+ id=41
+ connect_to=61
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=42
+ x=13
+ y=2
+ port=invalue1
+ {
+ id=43
+ connect_to=93
+ }
+ port=invalue2
+ {
+ id=44
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=45
+ connect_to=53
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=46
+ x=5
+ y=4
+ port=frequency
+ {
+ id=47
+ connect_to=28
+ }
+ port=pos
+ {
+ id=48
+ connect_to=30
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=49
+ x=9
+ y=4
+ port=frequency
+ {
+ id=50
+ connect_to=35
+ }
+ port=pos
+ {
+ id=51
+ connect_to=37
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=52
+ x=13
+ y=4
+ port=frequency
+ {
+ id=53
+ connect_to=45
+ }
+ port=pos
+ {
+ id=54
+ connect_to=40
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=55
+ x=5
+ y=10
+ port=invalue1
+ {
+ id=56
+ connect_to=66
+ }
+ port=invalue2
+ {
+ id=57
+ connect_to=38
+ }
+ port=outvalue
+ {
+ id=58
+ connect_to=60
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=59
+ x=9
+ y=11
+ port=invalue1
+ {
+ id=60
+ connect_to=58
+ }
+ port=invalue2
+ {
+ id=61
+ connect_to=41
+ }
+ port=outvalue
+ {
+ id=62
+ connect_to=86
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=63
+ x=1
+ y=9
+ port=invalue1
+ {
+ id=64
+ connect_to=24
+ }
+ port=invalue2
+ {
+ id=65
+ connect_to=31
+ }
+ port=outvalue
+ {
+ id=66
+ connect_to=56
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=67
+ x=13
+ y=13
+ port=invalue1
+ {
+ id=68
+ connect_to=74
+ }
+ port=invalue2
+ {
+ id=69
+ audio_data=0.20000
+ }
+ port=outvalue
+ {
+ id=70
+ connect_to=9
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=71
+ x=13
+ y=11
+ port=invalue
+ {
+ id=72
+ connect_to=88
+ }
+ port=frequency
+ {
+ id=73
+ audio_data=5000.00000
+ }
+ port=outvalue
+ {
+ id=74
+ connect_to=68
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=75
+ x=17
+ y=2
+ port=invalue1
+ {
+ id=76
+ connect_to=93
+ }
+ port=invalue2
+ {
+ id=77
+ audio_data=4.00000
+ }
+ port=outvalue
+ {
+ id=78
+ connect_to=80
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=79
+ x=17
+ y=4
+ port=frequency
+ {
+ id=80
+ connect_to=78
+ }
+ port=pos
+ {
+ id=81
+ connect_to=83
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=82
+ x=17
+ y=6
+ port=pos
+ {
+ id=83
+ connect_to=81
+ }
+ port=outvalue
+ {
+ id=84
+ connect_to=87
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=85
+ x=17
+ y=9
+ port=invalue1
+ {
+ id=86
+ connect_to=62
+ }
+ port=invalue2
+ {
+ id=87
+ connect_to=84
+ }
+ port=outvalue
+ {
+ id=88
+ connect_to=72
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=16
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=90
+ connect_to=14
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=16
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=91
+ connect_to=14
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=16
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=92
+ connect_to=15
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=93
+ connect_to=5
+ connect_to=26
+ connect_to=33
+ connect_to=43
+ connect_to=76
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=94
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=95
+ connect_to=8
+ }
+}
diff --git a/arts/examples/instrument_simple_sin.arts b/arts/examples/instrument_simple_sin.arts
new file mode 100644
index 00000000..e2725a8f
--- /dev/null
+++ b/arts/examples/instrument_simple_sin.arts
@@ -0,0 +1,190 @@
+name=instrument_simple_sin
+module=Arts::Synth_FREQUENCY
+{
+ id=4
+ x=1
+ y=2
+ port=frequency
+ {
+ id=5
+ connect_to=29
+ }
+ port=pos
+ {
+ id=6
+ connect_to=8
+ }
+}
+module=Arts::Synth_WAVE_SIN
+{
+ id=7
+ x=2
+ y=3
+ port=pos
+ {
+ id=8
+ connect_to=6
+ }
+ port=outvalue
+ {
+ id=9
+ connect_to=12
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=10
+ x=2
+ y=5
+ port=active
+ {
+ id=11
+ connect_to=31
+ }
+ port=invalue
+ {
+ id=12
+ connect_to=9
+ }
+ port=attack
+ {
+ id=13
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=14
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=15
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=16
+ audio_data=0.20000
+ }
+ port=outvalue
+ {
+ id=17
+ connect_to=23
+ connect_to=24
+ connect_to=26
+ connect_to=27
+ }
+ port=done
+ {
+ id=18
+ connect_to=20
+ connect_to=28
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=7
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=26
+ connect_to=17
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=7
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=27
+ connect_to=17
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=7
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=28
+ connect_to=18
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=29
+ connect_to=5
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=30
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=31
+ connect_to=11
+ }
+}
diff --git a/arts/examples/instrument_simple_square.arts b/arts/examples/instrument_simple_square.arts
new file mode 100644
index 00000000..d82297e3
--- /dev/null
+++ b/arts/examples/instrument_simple_square.arts
@@ -0,0 +1,190 @@
+name=instrument_simple_square
+module=Arts::Synth_FREQUENCY
+{
+ id=4
+ x=1
+ y=2
+ port=frequency
+ {
+ id=5
+ connect_to=29
+ }
+ port=pos
+ {
+ id=6
+ connect_to=23
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=7
+ x=3
+ y=6
+ port=active
+ {
+ id=8
+ connect_to=31
+ }
+ port=invalue
+ {
+ id=9
+ connect_to=24
+ }
+ port=attack
+ {
+ id=10
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=11
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=12
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=13
+ audio_data=0.20000
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=20
+ connect_to=21
+ connect_to=26
+ connect_to=27
+ }
+ port=done
+ {
+ id=15
+ connect_to=17
+ connect_to=28
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=22
+ x=1
+ y=4
+ port=pos
+ {
+ id=23
+ connect_to=6
+ }
+ port=outvalue
+ {
+ id=24
+ connect_to=9
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=8
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=26
+ connect_to=14
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=8
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=27
+ connect_to=14
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=8
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=28
+ connect_to=15
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=29
+ connect_to=5
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=30
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=31
+ connect_to=8
+ }
+}
diff --git a/arts/examples/instrument_simple_tri.arts b/arts/examples/instrument_simple_tri.arts
new file mode 100644
index 00000000..05453b8b
--- /dev/null
+++ b/arts/examples/instrument_simple_tri.arts
@@ -0,0 +1,304 @@
+name=instrument_simple_tri
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=0
+ y=2
+ port=frequency
+ {
+ id=1
+ connect_to=36
+ }
+ port=pos
+ {
+ id=2
+ connect_to=13
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=3
+ x=4
+ y=9
+ port=active
+ {
+ id=4
+ connect_to=38
+ }
+ port=invalue
+ {
+ id=5
+ connect_to=46
+ }
+ port=attack
+ {
+ id=6
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=7
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=8
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=9
+ audio_data=0.20000
+ }
+ port=outvalue
+ {
+ id=10
+ connect_to=33
+ connect_to=34
+ }
+ port=done
+ {
+ id=11
+ connect_to=35
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=12
+ x=1
+ y=3
+ port=pos
+ {
+ id=13
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=26
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=15
+ x=6
+ y=6
+ port=invalue
+ {
+ id=16
+ connect_to=28
+ }
+ port=frequency
+ {
+ id=17
+ audio_data=4000.00000
+ }
+ port=outvalue
+ {
+ id=18
+ connect_to=44
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=19
+ x=9
+ y=3
+ port=pos
+ {
+ id=20
+ connect_to=24
+ }
+ port=outvalue
+ {
+ id=21
+ connect_to=27
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=22
+ x=8
+ y=2
+ port=frequency
+ {
+ id=23
+ connect_to=32
+ }
+ port=pos
+ {
+ id=24
+ connect_to=20
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=25
+ x=5
+ y=5
+ port=invalue1
+ {
+ id=26
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=27
+ connect_to=21
+ }
+ port=outvalue
+ {
+ id=28
+ connect_to=16
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=29
+ x=7
+ y=1
+ port=invalue1
+ {
+ id=30
+ connect_to=36
+ }
+ port=invalue2
+ {
+ id=31
+ audio_data=1.01000
+ }
+ port=outvalue
+ {
+ id=32
+ connect_to=23
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=43
+ x=7
+ y=7
+ port=invalue1
+ {
+ id=44
+ connect_to=18
+ }
+ port=invalue2
+ {
+ id=45
+ audio_data=0.50000
+ }
+ port=outvalue
+ {
+ id=46
+ connect_to=5
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=12
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=33
+ connect_to=10
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=12
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=34
+ connect_to=10
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=12
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=35
+ connect_to=11
+ }
+}
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=36
+ connect_to=1
+ connect_to=30
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=37
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=38
+ connect_to=4
+ }
+}
diff --git a/arts/examples/instrument_slide.arts b/arts/examples/instrument_slide.arts
new file mode 100644
index 00000000..cb2949b0
--- /dev/null
+++ b/arts/examples/instrument_slide.arts
@@ -0,0 +1,464 @@
+name=instrument_slide
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=4
+ y=3
+ port=frequency
+ {
+ id=1
+ connect_to=67
+ }
+ port=pos
+ {
+ id=2
+ connect_to=22
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=3
+ x=12
+ y=3
+ port=active
+ {
+ id=4
+ connect_to=69
+ }
+ port=invalue
+ {
+ id=5
+ connect_to=19
+ }
+ port=attack
+ {
+ id=6
+ audio_data=0.00200
+ }
+ port=decay
+ {
+ id=7
+ audio_data=0.05000
+ }
+ port=sustain
+ {
+ id=8
+ audio_data=0.70000
+ }
+ port=release
+ {
+ id=9
+ audio_data=0.05000
+ }
+ port=outvalue
+ {
+ id=10
+ connect_to=33
+ connect_to=60
+ }
+ port=done
+ {
+ id=11
+ connect_to=70
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=12
+ x=12
+ y=1
+ port=active
+ {
+ id=13
+ connect_to=69
+ }
+ port=invalue
+ {
+ id=14
+ connect_to=68
+ }
+ port=attack
+ {
+ id=15
+ audio_data=0.00200
+ }
+ port=decay
+ {
+ id=16
+ audio_data=2.00000
+ }
+ port=sustain
+ {
+ id=17
+ audio_data=0.00010
+ }
+ port=release
+ {
+ id=18
+ audio_data=0.10000
+ }
+ port=outvalue
+ {
+ id=19
+ connect_to=5
+ }
+ port=done
+ {
+ id=20
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=21
+ x=5
+ y=4
+ port=pos
+ {
+ id=22
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=23
+ connect_to=48
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=24
+ x=5
+ y=11
+ port=invalue
+ {
+ id=25
+ connect_to=50
+ }
+ port=frequency
+ {
+ id=26
+ connect_to=66
+ }
+ port=outvalue
+ {
+ id=27
+ connect_to=29
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=28
+ x=6
+ y=12
+ port=invalue1
+ {
+ id=29
+ connect_to=27
+ }
+ port=invalue2
+ {
+ id=30
+ connect_to=62
+ }
+ port=outvalue
+ {
+ id=31
+ connect_to=71
+ connect_to=72
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=32
+ x=11
+ y=5
+ port=invalue1
+ {
+ id=33
+ connect_to=10
+ }
+ port=invalue2
+ {
+ id=34
+ audio_data=2000.00000
+ }
+ port=outvalue
+ {
+ id=35
+ connect_to=65
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=36
+ x=1
+ y=3
+ port=invalue1
+ {
+ id=37
+ connect_to=67
+ }
+ port=invalue2
+ {
+ id=38
+ audio_data=2.01000
+ }
+ port=outvalue
+ {
+ id=39
+ connect_to=41
+ connect_to=64
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=40
+ x=2
+ y=5
+ port=frequency
+ {
+ id=41
+ connect_to=39
+ }
+ port=pos
+ {
+ id=42
+ connect_to=44
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=43
+ x=3
+ y=6
+ port=pos
+ {
+ id=44
+ connect_to=42
+ }
+ port=outvalue
+ {
+ id=45
+ connect_to=47
+ }
+}
+module=Arts::Synth_XFADE
+{
+ id=46
+ x=4
+ y=7
+ port=invalue1
+ {
+ id=47
+ connect_to=45
+ }
+ port=invalue2
+ {
+ id=48
+ connect_to=23
+ }
+ port=percentage
+ {
+ id=49
+ connect_to=58
+ }
+ port=outvalue
+ {
+ id=50
+ connect_to=25
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=51
+ x=7
+ y=3
+ port=invalue1
+ {
+ id=52
+ connect_to=68
+ }
+ port=invalue2
+ {
+ id=53
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=54
+ connect_to=56
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=55
+ x=8
+ y=4
+ port=invalue1
+ {
+ id=56
+ connect_to=54
+ }
+ port=invalue2
+ {
+ id=57
+ audio_data=-1.00000
+ }
+ port=outvalue
+ {
+ id=58
+ connect_to=49
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=59
+ x=11
+ y=7
+ port=invalue1
+ {
+ id=60
+ connect_to=10
+ }
+ port=invalue2
+ {
+ id=61
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=62
+ connect_to=30
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=63
+ x=7
+ y=9
+ port=invalue1
+ {
+ id=64
+ connect_to=39
+ }
+ port=invalue2
+ {
+ id=65
+ connect_to=35
+ }
+ port=outvalue
+ {
+ id=66
+ connect_to=26
+ }
+}
+structureport
+{
+ name=frequency
+ x=5
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=67
+ connect_to=1
+ connect_to=37
+ }
+}
+structureport
+{
+ name=velocity
+ x=6
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=68
+ connect_to=14
+ connect_to=52
+ }
+}
+structureport
+{
+ name=pressed
+ x=7
+ y=0
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=69
+ connect_to=4
+ connect_to=13
+ }
+}
+structureport
+{
+ name=done
+ x=15
+ y=14
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=70
+ connect_to=11
+ }
+}
+structureport
+{
+ name=left
+ x=6
+ y=14
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=71
+ connect_to=31
+ }
+}
+structureport
+{
+ name=right
+ x=8
+ y=14
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=72
+ connect_to=31
+ }
+}
diff --git a/arts/examples/instrument_slide1.arts b/arts/examples/instrument_slide1.arts
new file mode 100644
index 00000000..f540e3fa
--- /dev/null
+++ b/arts/examples/instrument_slide1.arts
@@ -0,0 +1,467 @@
+name=instrument_slide1
+module=Arts::Synth_FREQUENCY
+{
+ id=4
+ x=4
+ y=3
+ port=frequency
+ {
+ id=5
+ connect_to=81
+ }
+ port=pos
+ {
+ id=6
+ connect_to=32
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=9
+ x=12
+ y=3
+ port=active
+ {
+ id=10
+ connect_to=83
+ }
+ port=invalue
+ {
+ id=11
+ connect_to=29
+ }
+ port=attack
+ {
+ id=12
+ audio_data=0.00200
+ }
+ port=decay
+ {
+ id=13
+ audio_data=0.05000
+ }
+ port=sustain
+ {
+ id=14
+ audio_data=0.70000
+ }
+ port=release
+ {
+ id=15
+ audio_data=0.05000
+ }
+ port=outvalue
+ {
+ id=16
+ connect_to=43
+ connect_to=70
+ }
+ port=done
+ {
+ id=17
+ connect_to=8
+ connect_to=80
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=22
+ x=12
+ y=1
+ port=active
+ {
+ id=23
+ connect_to=83
+ }
+ port=invalue
+ {
+ id=24
+ connect_to=82
+ }
+ port=attack
+ {
+ id=25
+ audio_data=0.00200
+ }
+ port=decay
+ {
+ id=26
+ audio_data=2.00000
+ }
+ port=sustain
+ {
+ id=27
+ audio_data=0.00010
+ }
+ port=release
+ {
+ id=28
+ audio_data=0.10000
+ }
+ port=outvalue
+ {
+ id=29
+ connect_to=11
+ }
+ port=done
+ {
+ id=30
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=31
+ x=5
+ y=4
+ port=pos
+ {
+ id=32
+ connect_to=6
+ }
+ port=outvalue
+ {
+ id=33
+ connect_to=58
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=34
+ x=5
+ y=11
+ port=invalue
+ {
+ id=35
+ connect_to=60
+ }
+ port=frequency
+ {
+ id=36
+ connect_to=76
+ }
+ port=outvalue
+ {
+ id=37
+ connect_to=39
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=38
+ x=6
+ y=12
+ port=invalue1
+ {
+ id=39
+ connect_to=37
+ }
+ port=invalue2
+ {
+ id=40
+ connect_to=72
+ }
+ port=outvalue
+ {
+ id=41
+ connect_to=20
+ connect_to=21
+ connect_to=78
+ connect_to=79
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=42
+ x=11
+ y=5
+ port=invalue1
+ {
+ id=43
+ connect_to=16
+ }
+ port=invalue2
+ {
+ id=44
+ audio_data=2000.00000
+ }
+ port=outvalue
+ {
+ id=45
+ connect_to=75
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=46
+ x=1
+ y=3
+ port=invalue1
+ {
+ id=47
+ connect_to=81
+ }
+ port=invalue2
+ {
+ id=48
+ audio_data=2.01000
+ }
+ port=outvalue
+ {
+ id=49
+ connect_to=51
+ connect_to=74
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=50
+ x=2
+ y=5
+ port=frequency
+ {
+ id=51
+ connect_to=49
+ }
+ port=pos
+ {
+ id=52
+ connect_to=54
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=53
+ x=3
+ y=6
+ port=pos
+ {
+ id=54
+ connect_to=52
+ }
+ port=outvalue
+ {
+ id=55
+ connect_to=57
+ }
+}
+module=Arts::Synth_XFADE
+{
+ id=56
+ x=4
+ y=7
+ port=invalue1
+ {
+ id=57
+ connect_to=55
+ }
+ port=invalue2
+ {
+ id=58
+ connect_to=33
+ }
+ port=percentage
+ {
+ id=59
+ connect_to=68
+ }
+ port=outvalue
+ {
+ id=60
+ connect_to=35
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=61
+ x=7
+ y=3
+ port=invalue1
+ {
+ id=62
+ connect_to=82
+ }
+ port=invalue2
+ {
+ id=63
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=64
+ connect_to=66
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=65
+ x=8
+ y=4
+ port=invalue1
+ {
+ id=66
+ connect_to=64
+ }
+ port=invalue2
+ {
+ id=67
+ audio_data=-1.00000
+ }
+ port=outvalue
+ {
+ id=68
+ connect_to=59
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=69
+ x=11
+ y=7
+ port=invalue1
+ {
+ id=70
+ connect_to=16
+ }
+ port=invalue2
+ {
+ id=71
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=72
+ connect_to=40
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=73
+ x=7
+ y=9
+ port=invalue1
+ {
+ id=74
+ connect_to=49
+ }
+ port=invalue2
+ {
+ id=75
+ connect_to=45
+ }
+ port=outvalue
+ {
+ id=76
+ connect_to=36
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=14
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=78
+ connect_to=41
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=14
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=79
+ connect_to=41
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=14
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=80
+ connect_to=17
+ }
+}
+structureport
+{
+ name=frequency
+ x=0
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=81
+ connect_to=47
+ connect_to=5
+ }
+}
+structureport
+{
+ name=velocity
+ x=2
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=82
+ connect_to=62
+ connect_to=24
+ }
+}
+structureport
+{
+ name=pressed
+ x=4
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=83
+ connect_to=23
+ connect_to=10
+ }
+}
diff --git a/arts/examples/instrument_square.arts b/arts/examples/instrument_square.arts
new file mode 100644
index 00000000..13d1e6ed
--- /dev/null
+++ b/arts/examples/instrument_square.arts
@@ -0,0 +1,465 @@
+name=instrument_square
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=2
+ port=frequency
+ {
+ id=1
+ connect_to=63
+ }
+ port=pos
+ {
+ id=2
+ connect_to=13
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=3
+ x=0
+ y=9
+ port=active
+ {
+ id=4
+ connect_to=65
+ }
+ port=invalue
+ {
+ id=5
+ connect_to=76
+ }
+ port=attack
+ {
+ id=6
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=7
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=8
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=9
+ audio_data=0.30000
+ }
+ port=outvalue
+ {
+ id=10
+ connect_to=66
+ connect_to=67
+ }
+ port=done
+ {
+ id=11
+ connect_to=68
+ }
+}
+module=Arts::Synth_WAVE_SQUARE
+{
+ id=12
+ x=1
+ y=4
+ port=pos
+ {
+ id=13
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=16
+ connect_to=21
+ connect_to=28
+ connect_to=52
+ connect_to=56
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=15
+ x=6
+ y=6
+ port=invalue1
+ {
+ id=16
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=17
+ connect_to=38
+ }
+ port=outvalue
+ {
+ id=18
+ connect_to=24
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=19
+ x=15
+ y=6
+ port=invalue1
+ {
+ id=20
+ connect_to=26
+ }
+ port=invalue2
+ {
+ id=21
+ connect_to=14
+ }
+ port=outvalue
+ {
+ id=22
+ connect_to=48
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=23
+ x=10
+ y=6
+ port=invalue1
+ {
+ id=24
+ connect_to=18
+ }
+ port=invalue2
+ {
+ id=25
+ connect_to=42
+ }
+ port=outvalue
+ {
+ id=26
+ connect_to=20
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=27
+ x=6
+ y=2
+ port=invalue1
+ {
+ id=28
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=29
+ audio_data=2.00000
+ }
+ port=outvalue
+ {
+ id=30
+ connect_to=32
+ connect_to=36
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=31
+ x=10
+ y=2
+ port=invalue1
+ {
+ id=32
+ connect_to=30
+ }
+ port=invalue2
+ {
+ id=33
+ audio_data=16.00000
+ }
+ port=outvalue
+ {
+ id=34
+ connect_to=40
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=35
+ x=6
+ y=4
+ port=invalue
+ {
+ id=36
+ connect_to=30
+ }
+ port=frequency
+ {
+ id=37
+ audio_data=6000.00000
+ }
+ port=outvalue
+ {
+ id=38
+ connect_to=17
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=39
+ x=10
+ y=4
+ port=invalue
+ {
+ id=40
+ connect_to=34
+ }
+ port=frequency
+ {
+ id=41
+ audio_data=2000.00000
+ }
+ port=outvalue
+ {
+ id=42
+ connect_to=25
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=43
+ x=12
+ y=9
+ port=invalue
+ {
+ id=44
+ connect_to=54
+ }
+ port=frequency
+ {
+ id=45
+ audio_data=8000.00000
+ }
+ port=outvalue
+ {
+ id=46
+ connect_to=60
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=47
+ x=16
+ y=7
+ port=invalue1
+ {
+ id=48
+ connect_to=22
+ }
+ port=invalue2
+ {
+ id=49
+ audio_data=0.10000
+ }
+ port=outvalue
+ {
+ id=50
+ connect_to=53
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=51
+ x=16
+ y=9
+ port=invalue1
+ {
+ id=52
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=53
+ connect_to=50
+ }
+ port=outvalue
+ {
+ id=54
+ connect_to=44
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=55
+ x=8
+ y=11
+ port=invalue1
+ {
+ id=56
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=57
+ connect_to=62
+ }
+ port=outvalue
+ {
+ id=58
+ connect_to=75
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=59
+ x=8
+ y=9
+ port=invalue1
+ {
+ id=60
+ connect_to=46
+ }
+ port=invalue2
+ {
+ id=61
+ audio_data=0.50000
+ }
+ port=outvalue
+ {
+ id=62
+ connect_to=57
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=73
+ x=0
+ y=7
+ port=invalue1
+ {
+ id=74
+ audio_data=0.30000
+ }
+ port=invalue2
+ {
+ id=75
+ connect_to=58
+ }
+ port=outvalue
+ {
+ id=76
+ connect_to=5
+ }
+}
+structureport
+{
+ name=frequency
+ x=2
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=63
+ connect_to=1
+ }
+}
+structureport
+{
+ name=velocity
+ x=4
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=64
+ }
+}
+structureport
+{
+ name=pressed
+ x=1
+ y=8
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=65
+ connect_to=4
+ }
+}
+structureport
+{
+ name=left
+ x=2
+ y=11
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=66
+ connect_to=10
+ }
+}
+structureport
+{
+ name=right
+ x=4
+ y=11
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=67
+ connect_to=10
+ }
+}
+structureport
+{
+ name=done
+ x=6
+ y=11
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=68
+ connect_to=11
+ }
+}
diff --git a/arts/examples/instrument_tri.arts b/arts/examples/instrument_tri.arts
new file mode 100644
index 00000000..2d5795a9
--- /dev/null
+++ b/arts/examples/instrument_tri.arts
@@ -0,0 +1,348 @@
+name=instrument_tri
+module=Arts::Synth_FREQUENCY
+{
+ id=0
+ x=1
+ y=2
+ port=frequency
+ {
+ id=1
+ connect_to=44
+ }
+ port=pos
+ {
+ id=2
+ connect_to=13
+ }
+}
+module=Arts::Synth_ENVELOPE_ADSR
+{
+ id=3
+ x=3
+ y=10
+ port=active
+ {
+ id=4
+ connect_to=46
+ }
+ port=invalue
+ {
+ id=5
+ connect_to=54
+ }
+ port=attack
+ {
+ id=6
+ audio_data=0.03000
+ }
+ port=decay
+ {
+ id=7
+ audio_data=0.10000
+ }
+ port=sustain
+ {
+ id=8
+ audio_data=0.60000
+ }
+ port=release
+ {
+ id=9
+ audio_data=0.20000
+ }
+ port=outvalue
+ {
+ id=10
+ connect_to=41
+ connect_to=42
+ }
+ port=done
+ {
+ id=11
+ connect_to=43
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=12
+ x=2
+ y=3
+ port=pos
+ {
+ id=13
+ connect_to=2
+ }
+ port=outvalue
+ {
+ id=14
+ connect_to=26
+ }
+}
+module=Arts::Synth_SHELVE_CUTOFF
+{
+ id=15
+ x=6
+ y=7
+ port=invalue
+ {
+ id=16
+ connect_to=28
+ }
+ port=frequency
+ {
+ id=17
+ connect_to=36
+ }
+ port=outvalue
+ {
+ id=18
+ connect_to=53
+ }
+}
+module=Arts::Synth_WAVE_TRI
+{
+ id=19
+ x=9
+ y=4
+ port=pos
+ {
+ id=20
+ connect_to=24
+ }
+ port=outvalue
+ {
+ id=21
+ connect_to=27
+ }
+}
+module=Arts::Synth_FREQUENCY
+{
+ id=22
+ x=8
+ y=3
+ port=frequency
+ {
+ id=23
+ connect_to=32
+ }
+ port=pos
+ {
+ id=24
+ connect_to=20
+ }
+}
+module=Arts::Synth_ADD
+{
+ id=25
+ x=6
+ y=5
+ port=invalue1
+ {
+ id=26
+ connect_to=14
+ }
+ port=invalue2
+ {
+ id=27
+ connect_to=21
+ }
+ port=outvalue
+ {
+ id=28
+ connect_to=16
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=29
+ x=7
+ y=1
+ port=invalue1
+ {
+ id=30
+ connect_to=44
+ }
+ port=invalue2
+ {
+ id=31
+ audio_data=1.01000
+ }
+ port=outvalue
+ {
+ id=32
+ connect_to=23
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=33
+ x=0
+ y=7
+ port=invalue1
+ {
+ id=34
+ connect_to=44
+ }
+ port=invalue2
+ {
+ id=35
+ connect_to=40
+ }
+ port=outvalue
+ {
+ id=36
+ connect_to=17
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=37
+ x=1
+ y=5
+ port=invalue1
+ {
+ id=38
+ audio_data=6.00000
+ }
+ port=invalue2
+ {
+ id=39
+ connect_to=45
+ }
+ port=outvalue
+ {
+ id=40
+ connect_to=35
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=51
+ x=6
+ y=8
+ port=invalue1
+ {
+ id=52
+ audio_data=0.50000
+ }
+ port=invalue2
+ {
+ id=53
+ connect_to=18
+ }
+ port=outvalue
+ {
+ id=54
+ connect_to=5
+ }
+}
+structureport
+{
+ name=left
+ x=2
+ y=12
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=41
+ connect_to=10
+ }
+}
+structureport
+{
+ name=right
+ x=4
+ y=12
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=42
+ connect_to=10
+ }
+}
+structureport
+{
+ name=done
+ x=6
+ y=12
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=43
+ connect_to=11
+ }
+}
+structureport
+{
+ name=frequency
+ x=2
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=44
+ connect_to=1
+ connect_to=30
+ connect_to=34
+ }
+}
+structureport
+{
+ name=velocity
+ x=4
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=45
+ connect_to=39
+ }
+}
+structureport
+{
+ name=pressed
+ x=6
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=46
+ connect_to=4
+ }
+}
diff --git a/arts/examples/mixer_element_eq.arts b/arts/examples/mixer_element_eq.arts
new file mode 100644
index 00000000..6123bb24
--- /dev/null
+++ b/arts/examples/mixer_element_eq.arts
@@ -0,0 +1,567 @@
+name=mixer_element_eq
+module=Arts::Widget
+{
+ id=0
+ x=6
+ y=1
+ port=widgetID
+ {
+ id=1
+ }
+ port=parent
+ {
+ id=2
+ }
+ port=x
+ {
+ id=3
+ }
+ port=y
+ {
+ id=4
+ }
+ port=width
+ {
+ id=5
+ }
+ port=height
+ {
+ id=6
+ }
+ port=visible
+ {
+ id=7
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+}
+module=Arts::Poti
+{
+ id=8
+ x=0
+ y=3
+ port=widgetID
+ {
+ id=9
+ }
+ port=x
+ {
+ id=11
+ }
+ port=y
+ {
+ id=12
+ }
+ port=width
+ {
+ id=13
+ }
+ port=height
+ {
+ id=14
+ }
+ port=visible
+ {
+ id=15
+ }
+ port=text
+ {
+ id=16
+ string_data=VOLUME
+ }
+ port=color
+ {
+ id=17
+ string_data=red
+ }
+ port=min
+ {
+ id=18
+ audio_data=0.00000
+ }
+ port=max
+ {
+ id=19
+ audio_data=1.00000
+ }
+ port=value
+ {
+ id=20
+ }
+}
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=21
+ x=8
+ y=4
+ port=busname
+ {
+ id=22
+ connect_to=119
+ }
+ port=left
+ {
+ id=23
+ connect_to=30
+ }
+ port=right
+ {
+ id=24
+ connect_to=34
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=25
+ x=1
+ y=21
+ port=busname
+ {
+ id=26
+ connect_to=118
+ }
+ port=left
+ {
+ id=27
+ connect_to=44
+ }
+ port=right
+ {
+ id=28
+ connect_to=52
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=29
+ x=0
+ y=7
+ port=invalue1
+ {
+ id=30
+ connect_to=23
+ }
+ port=invalue2
+ {
+ id=31
+ }
+ port=outvalue
+ {
+ id=32
+ connect_to=43
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=33
+ x=6
+ y=7
+ port=invalue1
+ {
+ id=34
+ connect_to=24
+ }
+ port=invalue2
+ {
+ id=35
+ }
+ port=outvalue
+ {
+ id=36
+ connect_to=51
+ }
+}
+module=Arts::Synth_STD_EQUALIZER
+{
+ id=37
+ x=0
+ y=17
+ port=low
+ {
+ id=38
+ }
+ port=mid
+ {
+ id=39
+ }
+ port=high
+ {
+ id=40
+ }
+ port=frequency
+ {
+ id=41
+ }
+ port=q
+ {
+ id=42
+ }
+ port=invalue
+ {
+ id=43
+ connect_to=32
+ }
+ port=outvalue
+ {
+ id=44
+ connect_to=27
+ }
+}
+module=Arts::Synth_STD_EQUALIZER
+{
+ id=45
+ x=7
+ y=17
+ port=low
+ {
+ id=46
+ }
+ port=mid
+ {
+ id=47
+ }
+ port=high
+ {
+ id=48
+ }
+ port=frequency
+ {
+ id=49
+ }
+ port=q
+ {
+ id=50
+ }
+ port=invalue
+ {
+ id=51
+ connect_to=36
+ }
+ port=outvalue
+ {
+ id=52
+ connect_to=28
+ }
+}
+module=Arts::Poti
+{
+ id=53
+ x=14
+ y=9
+ port=widgetID
+ {
+ id=54
+ }
+ port=x
+ {
+ id=56
+ }
+ port=y
+ {
+ id=57
+ }
+ port=width
+ {
+ id=58
+ }
+ port=height
+ {
+ id=59
+ }
+ port=visible
+ {
+ id=60
+ }
+ port=text
+ {
+ id=61
+ string_data=MID
+ }
+ port=color
+ {
+ id=62
+ string_data=darkblue
+ }
+ port=min
+ {
+ id=63
+ audio_data=-24.00000
+ }
+ port=max
+ {
+ id=64
+ audio_data=24.00000
+ }
+ port=value
+ {
+ id=65
+ }
+}
+module=Arts::Poti
+{
+ id=66
+ x=14
+ y=11
+ port=widgetID
+ {
+ id=67
+ }
+ port=x
+ {
+ id=69
+ }
+ port=y
+ {
+ id=70
+ }
+ port=width
+ {
+ id=71
+ }
+ port=height
+ {
+ id=72
+ }
+ port=visible
+ {
+ id=73
+ }
+ port=text
+ {
+ id=74
+ string_data=HIGH
+ }
+ port=color
+ {
+ id=75
+ string_data=darkblue
+ }
+ port=min
+ {
+ id=76
+ audio_data=-24.00000
+ }
+ port=max
+ {
+ id=77
+ audio_data=24.00000
+ }
+ port=value
+ {
+ id=78
+ }
+}
+module=Arts::Poti
+{
+ id=79
+ x=14
+ y=7
+ port=widgetID
+ {
+ id=80
+ }
+ port=x
+ {
+ id=82
+ }
+ port=y
+ {
+ id=83
+ }
+ port=width
+ {
+ id=84
+ }
+ port=height
+ {
+ id=85
+ }
+ port=visible
+ {
+ id=86
+ }
+ port=text
+ {
+ id=87
+ string_data=LOW
+ }
+ port=color
+ {
+ id=88
+ string_data=darkblue
+ }
+ port=min
+ {
+ id=89
+ audio_data=-24.00000
+ }
+ port=max
+ {
+ id=90
+ audio_data=24.00000
+ }
+ port=value
+ {
+ id=91
+ }
+}
+module=Arts::Poti
+{
+ id=92
+ x=14
+ y=13
+ port=widgetID
+ {
+ id=93
+ }
+ port=x
+ {
+ id=95
+ }
+ port=y
+ {
+ id=96
+ }
+ port=width
+ {
+ id=97
+ }
+ port=height
+ {
+ id=98
+ }
+ port=visible
+ {
+ id=99
+ }
+ port=text
+ {
+ id=100
+ string_data=FREQUENCY
+ }
+ port=color
+ {
+ id=101
+ string_data=darkgreen
+ }
+ port=min
+ {
+ id=102
+ audio_data=1.00000
+ }
+ port=max
+ {
+ id=103
+ audio_data=5000.00000
+ }
+ port=value
+ {
+ id=104
+ }
+}
+module=Arts::Poti
+{
+ id=105
+ x=14
+ y=15
+ port=widgetID
+ {
+ id=106
+ }
+ port=x
+ {
+ id=108
+ }
+ port=y
+ {
+ id=109
+ }
+ port=width
+ {
+ id=110
+ }
+ port=height
+ {
+ id=111
+ }
+ port=visible
+ {
+ id=112
+ }
+ port=text
+ {
+ id=113
+ string_data=Q
+ }
+ port=color
+ {
+ id=114
+ string_data=darkgreen
+ }
+ port=min
+ {
+ id=115
+ audio_data=0.10000
+ }
+ port=max
+ {
+ id=116
+ audio_data=2.00000
+ }
+ port=value
+ {
+ id=117
+ }
+}
+structureport
+{
+ name=output
+ x=4
+ y=20
+ position=2
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=118
+ connect_to=26
+ }
+}
+structureport
+{
+ name=input
+ x=13
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=119
+ connect_to=22
+ }
+}
+structureport
+{
+ name=parent
+ x=7
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=120
+ }
+}
diff --git a/arts/examples/mixer_element_eqfx.arts b/arts/examples/mixer_element_eqfx.arts
new file mode 100644
index 00000000..b7248fcb
--- /dev/null
+++ b/arts/examples/mixer_element_eqfx.arts
@@ -0,0 +1,740 @@
+name=mixer_element_eqfx
+module=Gui_SUB_PANEL
+{
+ id=147
+ x=6
+ y=1
+ port=parent
+ {
+ id=148
+ connect_to=279
+ }
+ port=x
+ {
+ id=149
+ audio_data=0.00000
+ }
+ port=y
+ {
+ id=150
+ audio_data=0.00000
+ }
+ port=width
+ {
+ id=151
+ audio_data=6.50000
+ }
+ port=height
+ {
+ id=152
+ audio_data=32.00000
+ }
+ port=pixmap
+ {
+ id=153
+ string_data=easyblue
+ }
+ port=id
+ {
+ id=154
+ connect_to=156
+ connect_to=183
+ connect_to=206
+ connect_to=216
+ connect_to=226
+ connect_to=236
+ connect_to=246
+ connect_to=256
+ }
+}
+module=Gui_POTI
+{
+ id=155
+ x=0
+ y=3
+ port=parent
+ {
+ id=156
+ connect_to=154
+ }
+ port=x
+ {
+ id=157
+ audio_data=1.00000
+ }
+ port=y
+ {
+ id=158
+ audio_data=2.00000
+ }
+ port=color
+ {
+ id=159
+ string_data=red
+ }
+ port=caption
+ {
+ id=160
+ string_data=VOLUME
+ }
+ port=min
+ {
+ id=161
+ audio_data=0.00000
+ }
+ port=max
+ {
+ id=162
+ audio_data=1.00000
+ }
+ port=initial
+ {
+ id=163
+ audio_data=1.00000
+ }
+ port=value
+ {
+ id=164
+ connect_to=176
+ connect_to=180
+ }
+}
+module=Synth_BUS_DOWNLINK
+{
+ id=165
+ x=8
+ y=4
+ port=clients
+ {
+ id=166
+ audio_data=1.00000
+ }
+ port=busname
+ {
+ id=167
+ connect_to=278
+ }
+ port=left
+ {
+ id=168
+ connect_to=175
+ }
+ port=right
+ {
+ id=169
+ connect_to=179
+ }
+}
+module=Synth_BUS_UPLINK
+{
+ id=170
+ x=1
+ y=21
+ port=left
+ {
+ id=171
+ connect_to=196
+ }
+ port=right
+ {
+ id=172
+ connect_to=204
+ }
+ port=busname
+ {
+ id=173
+ connect_to=277
+ }
+}
+module=Synth_MUL
+{
+ id=174
+ x=0
+ y=7
+ port=invalue
+ {
+ id=175
+ connect_to=168
+ }
+ port=faktor
+ {
+ id=176
+ connect_to=164
+ }
+ port=outvalue
+ {
+ id=177
+ connect_to=190
+ }
+}
+module=Synth_MUL
+{
+ id=178
+ x=6
+ y=7
+ port=invalue
+ {
+ id=179
+ connect_to=169
+ }
+ port=faktor
+ {
+ id=180
+ connect_to=164
+ }
+ port=outvalue
+ {
+ id=181
+ connect_to=198
+ }
+}
+module=Gui_LABEL
+{
+ id=182
+ x=13
+ y=4
+ port=parent
+ {
+ id=183
+ connect_to=154
+ }
+ port=x
+ {
+ id=184
+ audio_data=0.00000
+ }
+ port=y
+ {
+ id=185
+ audio_data=0.00000
+ }
+ port=color
+ {
+ id=186
+ string_data=#fff7a3
+ }
+ port=caption
+ {
+ id=187
+ connect_to=278
+ }
+ port=pixmap
+ {
+ id=188
+ string_data=easylabel
+ }
+}
+module=Synth_STD_EQUALIZER
+{
+ id=189
+ x=0
+ y=17
+ port=invalue
+ {
+ id=190
+ connect_to=177
+ }
+ port=low
+ {
+ id=191
+ connect_to=234
+ }
+ port=mid
+ {
+ id=192
+ connect_to=214
+ }
+ port=high
+ {
+ id=193
+ connect_to=224
+ }
+ port=frequency
+ {
+ id=194
+ connect_to=244
+ }
+ port=q
+ {
+ id=195
+ connect_to=254
+ }
+ port=outvalue
+ {
+ id=196
+ connect_to=171
+ connect_to=270
+ }
+}
+module=Synth_STD_EQUALIZER
+{
+ id=197
+ x=7
+ y=17
+ port=invalue
+ {
+ id=198
+ connect_to=181
+ }
+ port=low
+ {
+ id=199
+ connect_to=234
+ }
+ port=mid
+ {
+ id=200
+ connect_to=214
+ }
+ port=high
+ {
+ id=201
+ connect_to=224
+ }
+ port=frequency
+ {
+ id=202
+ connect_to=244
+ }
+ port=q
+ {
+ id=203
+ connect_to=254
+ }
+ port=outvalue
+ {
+ id=204
+ connect_to=172
+ connect_to=274
+ }
+}
+module=Gui_POTI
+{
+ id=205
+ x=14
+ y=9
+ port=parent
+ {
+ id=206
+ connect_to=154
+ }
+ port=x
+ {
+ id=207
+ audio_data=1.00000
+ }
+ port=y
+ {
+ id=208
+ audio_data=10.00000
+ }
+ port=color
+ {
+ id=209
+ string_data=darkblue
+ }
+ port=caption
+ {
+ id=210
+ string_data=MID
+ }
+ port=min
+ {
+ id=211
+ audio_data=-24.00000
+ }
+ port=max
+ {
+ id=212
+ audio_data=24.00000
+ }
+ port=initial
+ {
+ id=213
+ audio_data=0.00000
+ }
+ port=value
+ {
+ id=214
+ connect_to=192
+ connect_to=200
+ }
+}
+module=Gui_POTI
+{
+ id=215
+ x=14
+ y=11
+ port=parent
+ {
+ id=216
+ connect_to=154
+ }
+ port=x
+ {
+ id=217
+ audio_data=1.00000
+ }
+ port=y
+ {
+ id=218
+ audio_data=14.00000
+ }
+ port=color
+ {
+ id=219
+ string_data=darkblue
+ }
+ port=caption
+ {
+ id=220
+ string_data=HIGH
+ }
+ port=min
+ {
+ id=221
+ audio_data=-24.00000
+ }
+ port=max
+ {
+ id=222
+ audio_data=24.00000
+ }
+ port=initial
+ {
+ id=223
+ audio_data=0.00000
+ }
+ port=value
+ {
+ id=224
+ connect_to=193
+ connect_to=201
+ }
+}
+module=Gui_POTI
+{
+ id=225
+ x=14
+ y=7
+ port=parent
+ {
+ id=226
+ connect_to=154
+ }
+ port=x
+ {
+ id=227
+ audio_data=1.00000
+ }
+ port=y
+ {
+ id=228
+ audio_data=6.00000
+ }
+ port=color
+ {
+ id=229
+ string_data=darkblue
+ }
+ port=caption
+ {
+ id=230
+ string_data=LOW
+ }
+ port=min
+ {
+ id=231
+ audio_data=-24.00000
+ }
+ port=max
+ {
+ id=232
+ audio_data=24.00000
+ }
+ port=initial
+ {
+ id=233
+ audio_data=0.00000
+ }
+ port=value
+ {
+ id=234
+ connect_to=191
+ connect_to=199
+ }
+}
+module=Gui_POTI
+{
+ id=235
+ x=14
+ y=13
+ port=parent
+ {
+ id=236
+ connect_to=154
+ }
+ port=x
+ {
+ id=237
+ audio_data=1.00000
+ }
+ port=y
+ {
+ id=238
+ audio_data=18.00000
+ }
+ port=color
+ {
+ id=239
+ string_data=darkgreen
+ }
+ port=caption
+ {
+ id=240
+ string_data=FREQUENCY
+ }
+ port=min
+ {
+ id=241
+ audio_data=1.00000
+ }
+ port=max
+ {
+ id=242
+ audio_data=5000.00000
+ }
+ port=initial
+ {
+ id=243
+ audio_data=1000.00000
+ }
+ port=value
+ {
+ id=244
+ connect_to=194
+ connect_to=202
+ }
+}
+module=Gui_POTI
+{
+ id=245
+ x=14
+ y=15
+ port=parent
+ {
+ id=246
+ connect_to=154
+ }
+ port=x
+ {
+ id=247
+ audio_data=1.00000
+ }
+ port=y
+ {
+ id=248
+ audio_data=22.00000
+ }
+ port=color
+ {
+ id=249
+ string_data=darkgreen
+ }
+ port=caption
+ {
+ id=250
+ string_data=Q
+ }
+ port=min
+ {
+ id=251
+ audio_data=0.10000
+ }
+ port=max
+ {
+ id=252
+ audio_data=2.00000
+ }
+ port=initial
+ {
+ id=253
+ audio_data=1.00000
+ }
+ port=value
+ {
+ id=254
+ connect_to=195
+ connect_to=203
+ }
+}
+module=Gui_POTI
+{
+ id=255
+ x=14
+ y=17
+ port=parent
+ {
+ id=256
+ connect_to=154
+ }
+ port=x
+ {
+ id=257
+ audio_data=1.00000
+ }
+ port=y
+ {
+ id=258
+ audio_data=26.00000
+ }
+ port=color
+ {
+ id=259
+ string_data=grey
+ }
+ port=caption
+ {
+ id=260
+ string_data=EFFECT
+ }
+ port=min
+ {
+ id=261
+ audio_data=0.00000
+ }
+ port=max
+ {
+ id=262
+ audio_data=1.00000
+ }
+ port=initial
+ {
+ id=263
+ audio_data=0.00000
+ }
+ port=value
+ {
+ id=264
+ connect_to=271
+ connect_to=275
+ }
+}
+module=Synth_BUS_UPLINK
+{
+ id=265
+ x=12
+ y=22
+ port=left
+ {
+ id=266
+ connect_to=272
+ }
+ port=right
+ {
+ id=267
+ connect_to=276
+ }
+ port=busname
+ {
+ id=268
+ string_data=effect
+ }
+}
+module=Synth_MUL
+{
+ id=269
+ x=9
+ y=20
+ port=invalue
+ {
+ id=270
+ connect_to=196
+ }
+ port=faktor
+ {
+ id=271
+ connect_to=264
+ }
+ port=outvalue
+ {
+ id=272
+ connect_to=266
+ }
+}
+module=Synth_MUL
+{
+ id=273
+ x=12
+ y=20
+ port=invalue
+ {
+ id=274
+ connect_to=204
+ }
+ port=faktor
+ {
+ id=275
+ connect_to=264
+ }
+ port=outvalue
+ {
+ id=276
+ connect_to=267
+ }
+}
+structureport
+{
+ name=output
+ x=4
+ y=20
+ position=2
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=277
+ connect_to=173
+ }
+}
+structureport
+{
+ name=input
+ x=13
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=278
+ connect_to=167
+ connect_to=187
+ }
+}
+structureport
+{
+ name=parent
+ x=7
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=279
+ connect_to=148
+ }
+}
diff --git a/arts/examples/mixer_element_simple.arts b/arts/examples/mixer_element_simple.arts
new file mode 100644
index 00000000..01246090
--- /dev/null
+++ b/arts/examples/mixer_element_simple.arts
@@ -0,0 +1,235 @@
+name=mixer_element_simple
+module=Arts::Widget
+{
+ id=0
+ x=6
+ y=1
+ port=widgetID
+ {
+ id=1
+ }
+ port=parent
+ {
+ id=2
+ }
+ port=x
+ {
+ id=3
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=y
+ {
+ id=4
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=5
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=height
+ {
+ id=6
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=visible
+ {
+ id=7
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+}
+module=Arts::Poti
+{
+ id=8
+ x=0
+ y=3
+ port=widgetID
+ {
+ id=9
+ }
+ port=parent
+ {
+ id=10
+ }
+ port=x
+ {
+ id=11
+ any_data=value:000000056c6f6e67000000000400000064
+ }
+ port=y
+ {
+ id=12
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=13
+ any_data=value:000000056c6f6e67000000000400000032
+ }
+ port=height
+ {
+ id=14
+ any_data=value:000000056c6f6e67000000000400000032
+ }
+ port=visible
+ {
+ id=15
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+ port=text
+ {
+ id=16
+ string_data=VOLUME
+ }
+ port=color
+ {
+ id=17
+ string_data=red
+ }
+ port=min
+ {
+ id=18
+ audio_data=0.00000
+ }
+ port=max
+ {
+ id=19
+ audio_data=1.00000
+ }
+ port=value
+ {
+ id=20
+ audio_data=0.50000
+ }
+}
+module=Arts::Synth_BUS_DOWNLINK
+{
+ id=21
+ x=8
+ y=4
+ port=busname
+ {
+ id=22
+ }
+ port=left
+ {
+ id=23
+ connect_to=30
+ }
+ port=right
+ {
+ id=24
+ connect_to=34
+ }
+}
+module=Arts::Synth_BUS_UPLINK
+{
+ id=25
+ x=1
+ y=10
+ port=busname
+ {
+ id=26
+ }
+ port=left
+ {
+ id=27
+ connect_to=32
+ }
+ port=right
+ {
+ id=28
+ connect_to=36
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=29
+ x=0
+ y=7
+ port=invalue1
+ {
+ id=30
+ connect_to=23
+ }
+ port=invalue2
+ {
+ id=31
+ }
+ port=outvalue
+ {
+ id=32
+ connect_to=27
+ }
+}
+module=Arts::Synth_MUL
+{
+ id=33
+ x=3
+ y=7
+ port=invalue1
+ {
+ id=34
+ connect_to=24
+ }
+ port=invalue2
+ {
+ id=35
+ }
+ port=outvalue
+ {
+ id=36
+ connect_to=28
+ }
+}
+structureport
+{
+ name=output
+ x=13
+ y=10
+ position=2
+ type
+ {
+ direction=input
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=37
+ }
+}
+structureport
+{
+ name=input
+ x=13
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=38
+ }
+}
+structureport
+{
+ name=parent
+ x=7
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=39
+ }
+}
diff --git a/arts/examples/template_Empty_Structure.arts b/arts/examples/template_Empty_Structure.arts
new file mode 100644
index 00000000..c8df90c3
--- /dev/null
+++ b/arts/examples/template_Empty_Structure.arts
@@ -0,0 +1 @@
+name=template_Empty_Structure
diff --git a/arts/examples/template_Instrument.arts b/arts/examples/template_Instrument.arts
new file mode 100644
index 00000000..e555e424
--- /dev/null
+++ b/arts/examples/template_Instrument.arts
@@ -0,0 +1,103 @@
+name=template_Instrument
+structureport
+{
+ name=frequency
+ x=1
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=11
+ }
+}
+structureport
+{
+ name=velocity
+ x=3
+ y=0
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=12
+ }
+}
+structureport
+{
+ name=pressed
+ x=5
+ y=0
+ position=3
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=13
+ }
+}
+structureport
+{
+ name=left
+ x=1
+ y=8
+ position=0
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=14
+ }
+}
+structureport
+{
+ name=right
+ x=3
+ y=8
+ position=1
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=15
+ }
+}
+structureport
+{
+ name=done
+ x=5
+ y=8
+ position=2
+ type
+ {
+ direction=input
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=16
+ }
+}
diff --git a/arts/examples/template_Instrument_GUI.arts b/arts/examples/template_Instrument_GUI.arts
new file mode 100644
index 00000000..67db385e
--- /dev/null
+++ b/arts/examples/template_Instrument_GUI.arts
@@ -0,0 +1,91 @@
+name=template_Instrument_GUI
+module=Arts::Widget
+{
+ id=0
+ x=1
+ y=2
+ port=widgetID
+ {
+ id=1
+ }
+ port=parent
+ {
+ id=2
+ }
+ port=x
+ {
+ id=3
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=y
+ {
+ id=4
+ any_data=value:000000056c6f6e67000000000400000000
+ }
+ port=width
+ {
+ id=5
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=height
+ {
+ id=6
+ any_data=value:000000056c6f6e6700000000040000000a
+ }
+ port=visible
+ {
+ id=7
+ any_data=value:00000008626f6f6c65616e000000000101
+ }
+}
+structureport
+{
+ name=parent
+ x=2
+ y=1
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=8
+ }
+}
+structureport
+{
+ name=x
+ x=3
+ y=1
+ position=1
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=property
+ }
+ data
+ {
+ id=9
+ }
+}
+structureport
+{
+ name=y
+ x=4
+ y=1
+ position=2
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=property
+ }
+ data
+ {
+ id=10
+ }
+}
diff --git a/arts/examples/template_Mixer_Element.arts b/arts/examples/template_Mixer_Element.arts
new file mode 100644
index 00000000..40c3e63c
--- /dev/null
+++ b/arts/examples/template_Mixer_Element.arts
@@ -0,0 +1,176 @@
+name=template_Mixer_Element
+module=Gui_SUB_PANEL
+{
+ id=0
+ x=0
+ y=1
+ port=parent
+ {
+ id=1
+ connect_to=26
+ }
+ port=x
+ {
+ id=2
+ audio_data=0.00000
+ }
+ port=y
+ {
+ id=3
+ audio_data=0.00000
+ }
+ port=width
+ {
+ id=4
+ audio_data=6.50000
+ }
+ port=height
+ {
+ id=5
+ audio_data=7.50000
+ }
+ port=pixmap
+ {
+ id=6
+ string_data=easyblue
+ }
+ port=id
+ {
+ id=7
+ connect_to=18
+ }
+}
+module=Synth_BUS_DOWNLINK
+{
+ id=8
+ x=2
+ y=4
+ port=clients
+ {
+ id=9
+ audio_data=1.00000
+ }
+ port=busname
+ {
+ id=10
+ connect_to=25
+ }
+ port=left
+ {
+ id=11
+ }
+ port=right
+ {
+ id=12
+ }
+}
+module=Synth_BUS_UPLINK
+{
+ id=13
+ x=3
+ y=8
+ port=left
+ {
+ id=14
+ }
+ port=right
+ {
+ id=15
+ }
+ port=busname
+ {
+ id=16
+ connect_to=24
+ }
+}
+module=Gui_LABEL
+{
+ id=17
+ x=6
+ y=4
+ port=parent
+ {
+ id=18
+ connect_to=7
+ }
+ port=x
+ {
+ id=19
+ audio_data=0.00000
+ }
+ port=y
+ {
+ id=20
+ audio_data=0.00000
+ }
+ port=color
+ {
+ id=21
+ string_data=#fff7a3
+ }
+ port=caption
+ {
+ id=22
+ connect_to=25
+ }
+ port=pixmap
+ {
+ id=23
+ string_data=easylabel
+ }
+}
+structureport
+{
+ name=output
+ x=6
+ y=7
+ position=2
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=24
+ connect_to=16
+ }
+}
+structureport
+{
+ name=input
+ x=7
+ y=0
+ position=1
+ type
+ {
+ direction=output
+ datatype=string
+ conntype=property
+ }
+ data
+ {
+ id=25
+ connect_to=10
+ connect_to=22
+ }
+}
+structureport
+{
+ name=parent
+ x=1
+ y=0
+ position=0
+ type
+ {
+ direction=output
+ datatype=audio
+ conntype=stream
+ }
+ data
+ {
+ id=26
+ connect_to=1
+ }
+}
diff --git a/arts/gui/Makefile.am b/arts/gui/Makefile.am
new file mode 100644
index 00000000..380e6a8c
--- /dev/null
+++ b/arts/gui/Makefile.am
@@ -0,0 +1,7 @@
+if arts_within_KDE
+ARTS_BUILD_KDE_GUI=kde
+endif
+
+SUBDIRS = common $(ARTS_BUILD_KDE_GUI)
+
+DIST_SUBDIRS = common kde
diff --git a/arts/gui/common/GenericGuiFactory.mcopclass b/arts/gui/common/GenericGuiFactory.mcopclass
new file mode 100644
index 00000000..001dd5ff
--- /dev/null
+++ b/arts/gui/common/GenericGuiFactory.mcopclass
@@ -0,0 +1,3 @@
+Interface=Arts::GenericGuiFactory,Arts::GuiFactory,Arts::Object
+Language=C++
+Library=libartsgui.la
diff --git a/arts/gui/common/Makefile.am b/arts/gui/common/Makefile.am
new file mode 100644
index 00000000..9d82449f
--- /dev/null
+++ b/arts/gui/common/Makefile.am
@@ -0,0 +1,35 @@
+lib_LTLIBRARIES = libartsgui_idl.la libartsgui.la
+
+INCLUDES= -I$(arts_includes) -I$(top_builddir)/arts/runtime $(all_includes)
+
+libartsgui_idl_la_SOURCES = artsgui.cc
+libartsgui_idl_la_LIBADD = -lmcop $(LIBDL)
+libartsgui_idl_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) \
+ -no-undefined
+
+libartsgui_la_SOURCES = genericguifactory_impl.cc
+libartsgui_la_LIBADD = libartsgui_idl.la
+libartsgui_la_LDFLAGS = $(all_libraries) -no-undefined
+libartsgui_la_COMPILE_FIRST = artsgui.h
+
+artsgui.cc artsgui.h: $(srcdir)/artsgui.idl $(MCOPIDL)
+ $(MCOPIDL) -t -I$(includedir)/arts $(srcdir)/artsgui.idl
+
+artsgui.mcoptype: artsgui.h
+artsgui.mcopclass: artsgui.h
+
+DISTCLEANFILES = artsgui.cc artsgui.h \
+ artsgui.mcoptype artsgui.mcopclass
+
+####### install idl files
+
+artsincludedir = $(includedir)/arts
+artsinclude_HEADERS = artsgui.h artsgui.idl
+
+mcopclassdir = $(libdir)/mcop/Arts
+mcopclass_DATA = GenericGuiFactory.mcopclass
+
+mcoptypedir = $(libdir)/mcop
+mcoptype_DATA = artsgui.mcoptype artsgui.mcopclass
+
+artsgui.lo: artsgui.h
diff --git a/arts/gui/common/artsgui.idl b/arts/gui/common/artsgui.idl
new file mode 100644
index 00000000..a96b83b7
--- /dev/null
+++ b/arts/gui/common/artsgui.idl
@@ -0,0 +1,396 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 2002 Matthias Kretz <kretz@kde.org>
+ 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 artsgui.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.
+ */
+
+module Arts {
+ // MayGrow = 1,
+ // ExpMask = 2,
+ // MayShrink = 4
+ enum SizePolicy {
+ spFixed = 0,
+ spMinimum = 1,
+ spMaximum = 4,
+ spPreferred = 5,
+ spMinimumExpanding = 3,
+ spExpanding = 7,
+ spIgnored = 2
+ };
+
+ interface Widget {
+ readonly attribute long widgetID;
+
+ attribute Widget parent;
+ attribute long x,y,width,height;
+ attribute boolean visible;
+ attribute SizePolicy hSizePolicy;
+ attribute SizePolicy vSizePolicy;
+
+ void show();
+ void hide();
+ };
+
+ enum Shape {
+ NoFrame = 0,
+ Box = 0x0001,
+ Panel = 0x0002,
+ WinPanel = 0x0003,
+ HLine = 0x0004,
+ VLine = 0x0005,
+ StyledPanel = 0x0006,
+ PopupPanel = 0x0007,
+ MenuBarPanel = 0x0008,
+ ToolBarPanel = 0x0009,
+ LineEditPanel = 0x000a,
+ TabWidgetPanel = 0x000b,
+ MShape = 0x000f
+ };
+
+ enum Shadow {
+ Plain = 0x0010,
+ Raised = 0x0020,
+ Sunken = 0x0030,
+ MShadow = 0x00f0
+ };
+
+ interface Frame : Widget {
+ void constructor( Widget parent );
+
+ attribute long margin;
+ attribute long linewidth;
+ attribute long midlinewidth;
+
+ attribute long framestyle;
+ attribute Shape frameshape;
+ attribute Shadow frameshadow;
+ };
+
+ /**
+ Some alignmentflags used by various widgets.
+ Taken from Qt. (akrille)
+ */
+ enum Align {
+ AlignAuto=0,
+ AlignLeft=1,
+ AlignRight=2,
+ AlignHCenter=4,
+ AlignJustify=8,
+ AlignTop=16,
+ AlignBottom=32,
+ AlignVCenter=64,
+ AlignCenter=68
+ };
+
+ /**
+ Directions. From Qt. (akrille)
+ */
+ enum Direction { LeftToRight, RightToLeft, TopToBottom, BottomToTop };
+
+ /** The LayoutBox. - Arrange your widgets vertical or horizontal.
+
+ Usage is quite simple: Add the widgets you have in the right order
+ to the layoutbox by calling addWidget().
+ Thats it, no ._addChild or .parent with this widget.
+
+ For more information see QBoxLayout.
+ (akrille)
+ */
+ interface LayoutBox : Frame {
+ /// Sets the direction of the widgets. Can be changed on-the-fly.
+ attribute Direction direction;
+ /// Adds a widget with the stretch-factor and the alignment.
+ void addWidget( Widget widget, long stretch, long align );
+ void addWidget( Widget widget, long stretch );
+ void addWidget( Widget widget );
+ /// Inserts the Widget at the given position
+ void insertWidget( long position, Widget widget, long stretch, long align );
+ void insertWidget( long position, Widget widget, long stretch );
+ void insertWidget( long position, Widget widget );
+ /// Adds a stretch with stretch-factor.
+ void addStretch( long stretch );
+ void addStretch();
+ /// Adds a Spacer the given width or height according your direction.
+ void addSpace( long space );
+ /** [From QBoxLayout]
+ Limits the perpendicular dimension of the box (e.g. height if the
+ box is LeftToRight) to a minimum of size. Other constraints may
+ increase the limit.
+ */
+ void addStrut( long size );
+ /// Adds a separator (a horizontal/vertical line)
+ void addSeparator(long stretch, long align);
+ void addSeparator(long stretch);
+ void addSeparator();
+ /// Adds a line with width and space left/right (top/bottom)
+ void addLine(long width, long space, long stretch, long align);
+ void addLine(long width, long space, long stretch);
+ void addLine(long width, long space);
+ /// The spacing between all widgets.
+ attribute long spacing;
+ /// The margin at the outsideborder.
+ attribute long layoutmargin;
+ };
+
+ /** IMHO (akrille) this should be removed and everywhere replaced with the LayoutBox... */
+ interface HBox : Frame {
+ attribute long spacing;
+ };
+
+ interface VBox : Frame {
+ attribute long spacing;
+ };
+
+ /** The PopupBox. - It can hide the widgets inside or show them as an own window.
+
+ Usage is quite simple: Create the Widget you want to be hidable inside
+ a container like LayoutBox or a normal widget. Then create the PopupBox
+ and call <Name_of_PopupBox>.widget( <Name_of_your_Container> ).
+ Thats it, no ._addChild or .parent with this widget.
+ (akrille)
+ */
+ interface PopupBox : Frame {
+ /// The direction of the PopupBox.
+ attribute Direction direction;
+ /// The name of the box, this gets shown inside the titlebar if its not inside but an own toplevel-widget.
+ attribute string name;
+ /// Sets the widget that is shown/hidden.
+ attribute Widget widget;
+ };
+
+ interface Button : Widget {
+ void constructor( Widget parent );
+ void constructor( string text, Widget parent );
+
+ attribute string text;
+ attribute boolean toggle;
+ readonly attribute boolean pressed;
+ readonly attribute boolean clicked; //clicked( true ) is emitted whenever the button
+ //is pressed an released with the mouse cursor
+ //still above the button
+ };
+
+ interface Poti : Frame {
+ attribute string caption, color;
+ attribute float min, max, value;
+ attribute float logarithmic;
+ attribute long range;
+ };
+
+ interface Fader : Widget {
+ void constructor( Widget parent );
+
+ attribute string caption, color;
+ attribute float min, max, value;
+ attribute float logarithmic;
+ };
+
+ interface LineEdit : Widget {
+ void constructor( Widget parent );
+
+ attribute string caption;
+ attribute string text;
+ };
+
+ interface SpinBox : Widget {
+ void constructor( Widget parent );
+
+ attribute string caption;
+ attribute long min, max, value;
+ };
+
+ interface ComboBox : Widget {
+ void constructor( Widget parent );
+
+ attribute string caption;
+ attribute sequence<string> choices;
+ attribute string value;
+ };
+
+ interface Graph : Widget {
+ void constructor( Widget parent );
+
+ attribute string caption;
+ attribute float minx, maxx, miny, maxy;
+ };
+
+ struct GraphPoint {
+ float x, y;
+ };
+ interface GraphLine {
+ attribute Graph graph;
+ attribute boolean editable;
+ attribute string color;
+ attribute sequence<GraphPoint> points;
+ };
+
+ enum TextBottom { South, North, West, East };
+
+ interface Label : Frame {
+ /// The text to show.
+ attribute string text;
+ /// The alignment of the text. See enum Align
+ attribute long align;
+ /// Fontsize [pixel]
+ /*writeonly*/ attribute long fontsize;
+ /// Fontfamily
+ /*writeonly*/ attribute string fontfamily;
+ /// Direction of the text in normal L-R-mode. Is used to rotate the text accordingly.
+ attribute TextBottom bottom;
+ };
+
+/// Some Notes:
+// - The calculation of the peak is very easy, but it can be changed without changing all styles..
+
+ /** * Styles for the LevelMeter. *
+ In Detail:
+ - lmNormalBars: <count> colored Bars.
+ - lmFireBars: One Bar moving up and down.
+ - lmLineBars: One Bar moving up and down, color depends on the invalue.
+ substyle:
+ - 0: various colors
+ - 1: one color (blue) with clipping (red). The old aRtsControl style.
+ - lmLEDs: <count> but not more than [height|width]/15 LEDs. (not yet implemented)
+ So minimum size of the LED's is 15 pixel.
+ substyle (first tree belong together others are to be or'ed):
+ - 1: Flat
+ - 2: Raised
+ - 3: Sunken
+ - 4: Circular (otherwise Rectangular)
+ - 8: SingleColor (otherwise in colors green/yellow/red)
+ - lmAnalog: An old-style analog VU-Meter. (not yet implemented)
+ - lmSmall: One Bar with the color depending on the invalue.
+ */
+ enum LevelMeterStyle { lmNormalBars, lmFireBars, lmLineBars, lmLEDs, lmAnalog, lmSmall };
+
+ /**
+ One LevelMeter
+ */
+ interface LevelMeter : Frame {
+ /**
+ The Style of the LevelMeter.
+ */
+ attribute LevelMeterStyle style;
+ /**
+ A substyle. Is different on every style;-)
+ */
+ attribute long substyle;
+ /**
+ How many Bars/LEDs it should have. If the size is smaller than
+ this count it will have only that many Bars. So set Count to something
+ very high for smooth vu-meters.
+ Note: not every Style will honor this.
+ Note2: Perhaps this could be integrated into substyle.
+ */
+ attribute long count;
+ /**
+ Sets the peakfalloff. Set to 0 to deactivate peaks.
+ Is used for weighting the average.
+ Peak is evaluated: ( peakfalloff * oldpeak + invalue ) / ( peakfalloff + 1 )
+ */
+ attribute long peakfalloff;
+ /**
+ Minimum and minimum dB for the LevelMeter.
+ Maximum should always be 0dB.
+ */
+ attribute float mindB, maxdB;
+ /**
+ The incomming signal...
+ This attribute always returns 0.0, altough it processes all its input.
+ */
+ /*writeonly*/ attribute float invalue;
+ /**
+ The Direction of the levelmeter from null-value to highest value.
+ */
+ attribute Direction direction;
+ };
+
+ /// Some positions.
+ enum Position { posLeft=0x0001, posRight=0x0002, posTop=0x0004, posBottom=0x0008 };
+
+ /// Tickmarks for LevelMeter / Fader / etc.
+ interface Tickmarks : Frame {
+ void constructor( float min, float max, Direction dir, long pos );
+ /// Minimum/Maximum shown value.
+ attribute float min, max;
+ /// The minimal stepsize for numbers, and substep for smaller marks.
+ attribute float minstep, substep;
+ /// Direction from min to max.
+ attribute Direction direction;
+ /**
+ * The position of the levelmeter/fader/etc which gets the marks.
+ * Only Left/Right are needed. As if direction is Up/Down...
+ * For stereotickmarks set this to posLeft|posRight.
+ */
+ attribute long position;
+ };
+
+ /// A Fader specially for volumes
+ // Maybe something can be ported to the normal Fader.
+ interface VolumeFader : Frame {
+ void constructor( float dbmin, float dbmax, Direction dir );
+ /// Minimum/Maximum values in dB
+ attribute float dbmin, dbmax;
+ /// Direction from min to max
+ attribute Direction direction;
+ /**
+ *The actual volume (calling this value only changes the gui and not the
+ * underlying/connected objects ie. doesn't send a change notification.)
+ */
+ attribute float volume;
+ /// The actual volume in dB (no change notification)
+ attribute float dbvolume;
+ };
+
+ /**
+ * A gui factory is an object that can create a Widget which provides a
+ * user interface for a running object (for instance, you might have an
+ * effect running somewhere, and a gui factory
+ *
+ * TODO: do we need another argument (or other arguments) to specify
+ * style or other parameters?
+ */
+ interface GuiFactory {
+ Widget createGui(object runningObject);
+ };
+
+ /**
+ * Convenience gui factory, which knows how and whether to
+ *
+ * - build a gui out of hints?
+ * - create an artsbuilder built gui?
+ * - create a gui composed of other widgets?
+ * - create a completely custom gui?
+ */
+ interface GenericGuiFactory : GuiFactory {
+ };
+};
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/common/genericguifactory_impl.cc b/arts/gui/common/genericguifactory_impl.cc
new file mode 100644
index 00000000..8a91b54f
--- /dev/null
+++ b/arts/gui/common/genericguifactory_impl.cc
@@ -0,0 +1,56 @@
+ /*
+
+ 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 "artsgui.h"
+#include "debug.h"
+
+using namespace Arts;
+using namespace std;
+
+namespace Arts {
+
+class GenericGuiFactory_impl : public GenericGuiFactory_skel {
+public:
+ Widget createGui(Object runningObject);
+};
+REGISTER_IMPLEMENTATION(GenericGuiFactory_impl);
+
+}
+
+Widget GenericGuiFactory_impl::createGui(Object runningObject)
+{
+ Arts::Widget result = Arts::Widget::null();
+ arts_return_val_if_fail(!runningObject.isNull(), result);
+
+ TraderQuery query;
+ query.supports("Interface","Arts::GuiFactory");
+ query.supports("CanCreate",runningObject._interfaceName());
+
+ vector<TraderOffer> *queryResults = query.query();
+ if(queryResults->size())
+ {
+ Arts::GuiFactory factory = SubClass((*queryResults)[0].interfaceName());
+ result = factory.createGui(runningObject);
+ }
+ delete queryResults;
+ return result;
+}
diff --git a/arts/gui/kde/Makefile.am b/arts/gui/kde/Makefile.am
new file mode 100644
index 00000000..5ebb3d0b
--- /dev/null
+++ b/arts/gui/kde/Makefile.am
@@ -0,0 +1,38 @@
+SUBDIRS = mcopclass
+
+lib_LTLIBRARIES = libartsgui_kde.la
+
+check_PROGRAMS = artstestgui dbtest
+
+INCLUDES= -I$(top_builddir)/arts/runtime -I$(top_builddir)/arts/gui/common -I$(arts_includes) $(all_includes)
+
+libartsgui_kde_la_SOURCES = kwidget_impl.cpp kbutton_impl.cpp \
+ kpoti_impl.cpp kpoti.cpp kwidgetrepo.cpp kartswidget.cpp \
+ klineedit_impl.cpp khbox_impl.cpp kvbox_impl.cpp kspinbox_impl.cpp \
+ kcombobox_impl.cpp kfader.cpp kfader_impl.cpp kgraph_impl.cpp kgraph.cpp \
+ kgraphline_impl.cpp kframe_impl.cpp klayoutbox_impl.cpp kpopupbox_impl.cpp \
+ klevelmeter_impl.cpp klevelmeter_small.cpp klevelmeter_linebars.cpp \
+ klevelmeter_normalbars.cpp klevelmeter_firebars.cpp \
+ ktickmarks_impl.cpp kvolumefader_impl.cpp klabel_impl.cpp
+
+libartsgui_kde_la_LIBADD = $(LIB_KIO) -lkdecore -lkdeui \
+ $(top_builddir)/arts/gui/common/libartsgui_idl.la
+libartsgui_kde_la_LDFLAGS = $(all_libraries) -no-undefined
+libartsgui_kde_la_COMPILE_FIRST = ../common/artsgui.h
+
+artstestgui_SOURCES = artstestgui.cpp
+artstestgui_LDADD = -lqtmcop -lkdecore -lartsflow \
+ $(top_builddir)/arts/gui/common/libartsgui_idl.la
+artstestgui_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+dbtest_SOURCES = dbtest.cpp
+dbtest_LDADD = -lqtmcop -lkdecore -lartsflow \
+ $(top_builddir)/arts/gui/kde/libartsgui_kde.la
+dbtest_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+libartsgui_kde_la_METASOURCES = AUTO
+
+####### install header files
+
+artsincludedir = $(includedir)/arts
+artsinclude_HEADERS = kartswidget.h kframe_impl.h kwidget_impl.h kwidgetrepo.h klayoutbox_impl.h
diff --git a/arts/gui/kde/artstestgui.cpp b/arts/gui/kde/artstestgui.cpp
new file mode 100644
index 00000000..92f13163
--- /dev/null
+++ b/arts/gui/kde/artstestgui.cpp
@@ -0,0 +1,124 @@
+ /*
+
+ 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 "artsgui.h"
+#include <connect.h>
+#include <qiomanager.h>
+#include <qpushbutton.h>
+#include <kapplication.h>
+#include <objectmanager.h>
+
+using namespace Arts;
+
+int main(int argc, char **argv)
+{
+ QIOManager iomanager;
+ Dispatcher dispatcher(&iomanager);
+ KApplication application(argc, argv, "testgui");
+
+ ObjectManager::the()->provideCapability("kdegui");
+
+ Widget w;
+ w.width(500); w.height(350); w.show();
+
+ Button b;
+ b.parent(w);
+ b.x(10);
+ b.y(10);
+ b.width(100);
+ b.height(20);
+ b.text("Hello World");
+ b.show();
+
+ Button b2;
+ b2.parent(w);
+ b2.x(10);
+ b2.y(30);
+ b2.width(100);
+ b2.height(20);
+ b2.text("More World");
+ b2.show();
+
+ Poti p;
+ p.parent(w);
+ p.x(150);
+ p.y(10);
+ p.caption("delay (ms)");
+ p.color("red");
+ p.min(10);
+ p.max(100);
+ p.value(90);
+ p.show();
+
+ Poti q;
+ q.parent(w);
+ q.x(250);
+ q.y(10);
+ q.caption("delay (ms)");
+ q.color("blue");
+ q.min(10);
+ q.max(100);
+ q.value(90);
+ q.show();
+
+ Graph g;
+ g.parent(w);
+ g.x(50);
+ g.y(70);
+ g.width(400);
+ g.height(230);
+ g.caption("a graph");
+ g.minx(0.0);
+ g.maxx(1.0);
+ g.miny(0.0);
+ g.maxy(1.0);
+ g.show();
+
+ GraphLine gline;
+ gline.graph(g);
+ std::vector<GraphPoint> points;
+ points.push_back(GraphPoint(0, 1.0));
+ points.push_back(GraphPoint(0.5, 1.0));
+ points.push_back(GraphPoint(0.501, 0.0));
+ points.push_back(GraphPoint(1.0, 0.0));
+ gline.points(points);
+ gline.color("red");
+ gline.editable(true);
+
+ /* moves q if p is moved */
+ connect(p,"value_changed",q,"value");
+
+/*
+ connect(q,"value_changed",p,"value");
+
+ With the current assumptions that change notifications make, it is not
+ possible to connect p to q and q to p.
+
+ The reason is that the notification will only be delivered some time
+ in the future (due to the requirement that they are asynchronous, i.e.
+ do not cause the sender to block) - but this means that two different
+ change notifications (i.e. changed to 1.0, changed to 2.0) may move
+ in a cycle between the two objects p and q, if p and q are cross
+ connected. So don't cross connect ;).
+*/
+ return application.exec();
+}
diff --git a/arts/gui/kde/dbtest.cpp b/arts/gui/kde/dbtest.cpp
new file mode 100644
index 00000000..164b3630
--- /dev/null
+++ b/arts/gui/kde/dbtest.cpp
@@ -0,0 +1,42 @@
+
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kstdaction.h>
+#include <kactioncollection.h>
+#include <kdebug.h>
+
+#include <dbtest.h>
+#include <dbtest.moc>
+
+dBTestWidget::dBTestWidget( QWidget* p, const char* n ) : QWidget( p,n ), dB2VolCalc( -24,6 ) {
+kdDebug() << k_funcinfo << endl;
+ ( void* ) KStdAction::quit( this, SLOT( close() ), new KActionCollection( this ) );
+
+ for ( float i=0; i<=1; i+=0.25 )
+ kdDebug() << i << " : " << amptodb( i ) << "dB" <<endl;
+
+ for ( int i=-24; i<=0; i++ )
+ kdDebug() << i <<"db : " << dbtoamp( i ) << endl;
+}
+dBTestWidget::~dBTestWidget() {
+kdDebug() << k_funcinfo << endl;
+}
+
+int main( int argc, char* argv[] ) {
+
+ KAboutData aboutData( "dbtest", I18N_NOOP( "dBTest" ),
+ "0.1", "", KAboutData::License_GPL,
+ "(c) 2002, Arnold Krille" );
+ aboutData.addAuthor( "Arnold Krille", I18N_NOOP( "Creator" ), "arnold@arnoldarts.de");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+
+ KApplication app;
+
+ dBTestWidget* w = new dBTestWidget( 0 );
+ w->show();
+ app.setMainWidget( w );
+
+ return app.exec();
+}
diff --git a/arts/gui/kde/dbtest.h b/arts/gui/kde/dbtest.h
new file mode 100644
index 00000000..e7d996b0
--- /dev/null
+++ b/arts/gui/kde/dbtest.h
@@ -0,0 +1,16 @@
+
+#ifndef DBTESTWIDGET_H
+#define DBTESTWIDGET_H
+
+#include <qwidget.h>
+
+#include "dbvolcalc.h"
+
+class dBTestWidget : public QWidget, public dB2VolCalc {
+ Q_OBJECT
+public:
+ dBTestWidget( QWidget*, const char* =0 );
+ ~dBTestWidget();
+};
+
+#endif
diff --git a/arts/gui/kde/dbvolcalc.h b/arts/gui/kde/dbvolcalc.h
new file mode 100644
index 00000000..8d99bf59
--- /dev/null
+++ b/arts/gui/kde/dbvolcalc.h
@@ -0,0 +1,82 @@
+/*
+ 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_DB2VOL_CALC_H
+#define ARTS_DB2VOL_CALC_H
+
+#include <math.h>
+
+class dB2VolCalc {
+private:
+ float _base;
+public:
+ dB2VolCalc( float _dbmin, float _dbmax )
+ : _base( 6/log10( double(2) ) ) // Depends on what you measure: intensity(10), pressure(20), old artscontrol(6/lg2 (near 20))
+ , dbmax( _dbmax )
+ , dbmin( _dbmin )
+ {}
+
+ float dbmax, dbmin;
+ /**
+ Logarithmic/decimal valuation:
+ p = ampfactor ( linear )
+ db = dezibel ( logarithmic )
+ p = 10^( d/10 )
+ db = 10*lg( p )
+
+ artscontrol was using
+ db = 6/ln( 2 ) * ln( p )
+ which would be
+ db = 6/lg( 2 ) * lg( p )
+ */
+ float amptodb( float p ) {
+ float db = _base*log10( p );
+ if ( db < dbmin ) db = dbmin;
+ if ( db > dbmax ) db = dbmax;
+ return db;
+ }
+ float dbtoamp( float db ) {
+ float amp = pow( 10, db/_base );
+ if ( amp <= pow( 10, dbmin/_base ) ) amp = 0;
+ return amp;
+ }
+ /// With ndb = normalized dB (between 0 and 1)
+ float amptondb( float p ) {
+ return dbtondb( amptodb( p ) ); //- dbmin ) / ( dbmax - dbmin );
+ }
+ float ndbtoamp( float ndb ) {
+ return dbtoamp( ndb * ( dbmax - dbmin ) + dbmin );
+ }
+ /// Normalizes a dezibel value.
+ float dbtondb( float db ) {
+ return ( db - dbmin )/( dbmax - dbmin );
+ }
+ /// Normalizes a volume to a logarithmic value between 0 and 1.
+ float dbtovol( float db ) {
+ return ( db -dbmin )/( 0-dbmin );
+ }
+ /// Unnormalizes a dezibel value.
+ float ndbtodb( float ndb ) {
+ return ( ndb * ( dbmax-dbmin ) +dbmin );
+ }
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kartswidget.cpp b/arts/gui/kde/kartswidget.cpp
new file mode 100644
index 00000000..78f3bc3f
--- /dev/null
+++ b/arts/gui/kde/kartswidget.cpp
@@ -0,0 +1,89 @@
+ /*
+
+ Copyright (C) 2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 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.
+
+ */
+
+#include "kartswidget.h"
+#include "kwidgetrepo.h"
+#include "debug.h"
+#include "qlayout.h"
+
+class KArtsWidgetPrivate {
+public:
+ QHBoxLayout *layout;
+};
+
+KArtsWidget::KArtsWidget( QWidget* parent, const char* name )
+ :QWidget( parent, name ), _content( Arts::Widget::null() )
+{
+ d = new KArtsWidgetPrivate;
+ d->layout = new QHBoxLayout(this);
+}
+
+KArtsWidget::KArtsWidget( Arts::Widget content, QWidget* parent, const char* name )
+ :QWidget( parent, name ), _content( Arts::Widget::null())
+{
+ d = new KArtsWidgetPrivate;
+ d->layout = new QHBoxLayout(this);
+ setContent(content);
+}
+
+KArtsWidget::KArtsWidget( Arts::Widget content, QWidget* parent, const char* name, WFlags wflags )
+ :QWidget( parent, name, wflags ), _content( Arts::Widget::null() )
+{
+ d = new KArtsWidgetPrivate;
+ d->layout = new QHBoxLayout( this );
+ setContent( content );
+}
+
+KArtsWidget::KArtsWidget(QWidget* parent, const char* name, WFlags wflags )
+ :QWidget(parent, name, wflags ), _content(Arts::Widget::null())
+{
+ d = new KArtsWidgetPrivate;
+ d->layout = new QHBoxLayout(this);
+}
+
+KArtsWidget::~KArtsWidget()
+{
+ QWidget *contentAsWidget
+ = KWidgetRepo::the()->lookupQWidget(_content.widgetID());
+ contentAsWidget->reparent(0,QPoint(0,0),_content.visible());
+ delete d;
+ d = 0;
+}
+
+/* TODO: change content (reparent old widget away, reparent new widget here) */
+void KArtsWidget::setContent(Arts::Widget content)
+{
+ arts_return_if_fail(!content.isNull());
+ QWidget *contentAsWidget
+ = KWidgetRepo::the()->lookupQWidget(content.widgetID());
+ arts_return_if_fail(contentAsWidget != 0);
+
+ _content = content;
+ contentAsWidget->reparent(this,QPoint(0,0),content.visible());
+ d->layout->addWidget(contentAsWidget);
+}
+
+Arts::Widget KArtsWidget::content()
+{
+ return _content;
+}
diff --git a/arts/gui/kde/kartswidget.h b/arts/gui/kde/kartswidget.h
new file mode 100644
index 00000000..049e4657
--- /dev/null
+++ b/arts/gui/kde/kartswidget.h
@@ -0,0 +1,92 @@
+ /*
+
+ Copyright (C) 2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 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.
+
+ */
+
+#ifndef ARTS_GUI_KARTSWIDGET_H
+#define ARTS_GUI_KARTSWIDGET_H
+
+#include <qwidget.h>
+#include "artsgui.h"
+#include <kdelibs_export.h>
+class KArtsWidgetPrivate;
+
+/**
+ * KArtsWidget provides a simple way to treat Arts::Widget classes like
+ * native Qt widgets. Suppose you use Qt, and want to put an Arts::Widget
+ * type into a layout, you can do so using this code
+ *
+ * <pre>
+ * Arts::Widget widget = ...get widget from somewhere...;
+ * KArtsWidget *w = new KArtsWidget(widget, this);
+ * layout->addWidget(w);
+ * </pre>
+ *
+ * In line 2 of the code, the "this" is the parent widget (which is usually
+ * this in Qt code).
+ *
+ * The KArtsWidget class keeps a reference to the content widget, so the
+ * content widget will not be freed until the KArtsWidget gets destroyed.
+ */
+class KDE_EXPORT KArtsWidget : public QWidget {
+private:
+ KArtsWidgetPrivate *d;
+
+protected:
+ Arts::Widget _content;
+
+public:
+ /**
+ * creates a new KArtsWidget
+ */
+ KArtsWidget( QWidget* parent, const char* name );
+
+ /**
+ * creates a new KArtsWidget and sets the content to an Arts::Widget
+ */
+ KArtsWidget( Arts::Widget content, QWidget* parent, const char* name );
+
+ /**
+ * creates a new KArtsWidget with WidgetFlags and content
+ *
+ * BCI: should replace the above in the next major release. ( akrille )
+ */
+ KArtsWidget( Arts::Widget, QWidget* =0, const char* =0, WFlags =0 );
+ // same without the content
+ KArtsWidget( QWidget* =0, const char* =0, WFlags =0 );
+
+ /**
+ * destructor
+ */
+ ~KArtsWidget();
+
+ /**
+ * sets the content to a new Arts::Widget
+ */
+ void setContent(Arts::Widget content);
+
+ /**
+ * gets the content widget
+ */
+ Arts::Widget content();
+};
+
+#endif /* ARTS_GUI_KARTSWIDGET_H*/
diff --git a/arts/gui/kde/kbutton_impl.cpp b/arts/gui/kde/kbutton_impl.cpp
new file mode 100644
index 00000000..eca30fcd
--- /dev/null
+++ b/arts/gui/kde/kbutton_impl.cpp
@@ -0,0 +1,135 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 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 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 "kbutton_impl.h"
+#include "kbutton_impl.moc"
+
+using namespace Arts;
+using namespace std;
+
+KButtonMapper::KButtonMapper( KButton_impl *_impl, QPushButton *but )
+ : QObject( but, "KButtonMapper" )
+ , impl( _impl )
+ , button( but )
+{
+ connect( but, SIGNAL( pressed() ), this, SLOT( pressed() ) );
+ connect( but, SIGNAL( released() ), this, SLOT( released() ) );
+ connect( but, SIGNAL( toggled( bool ) ), this, SLOT( toggled( bool ) ) );
+ connect( but, SIGNAL( clicked() ), this, SLOT( clicked() ) );
+}
+
+void KButtonMapper::pressed()
+{
+ if( ! button->isToggleButton() )
+ impl->changeState(true);
+}
+
+void KButtonMapper::released()
+{
+ if( ! button->isToggleButton() )
+ impl->changeState(false);
+}
+
+void KButtonMapper::toggled( bool b )
+{
+ if( button->isToggleButton() )
+ impl->changeState( b );
+}
+
+void KButtonMapper::clicked()
+{
+ impl->emitClicked();
+}
+
+KButton_impl::KButton_impl( QPushButton * widget )
+ : KWidget_impl( widget ? widget : new QPushButton( 0 ) )
+ , _clicked( false )
+{
+ _qpushbutton = static_cast<QPushButton*>( _qwidget );
+ ( void )new KButtonMapper( this, _qpushbutton );
+}
+
+void KButton_impl::constructor( Widget p )
+{
+ parent( p );
+}
+
+void KButton_impl::constructor( const string & t, Widget p )
+{
+ parent( p );
+ text( t );
+}
+
+void KButton_impl::emitClicked()
+{
+ _clicked = true;
+ clicked_changed( true );
+}
+
+string KButton_impl::text()
+{
+ return _qpushbutton->text().utf8().data();
+}
+
+void KButton_impl::text(const string& newText)
+{
+ _qpushbutton->setText(QString::fromUtf8(newText.c_str()));
+}
+
+bool KButton_impl::toggle()
+{
+ return _qpushbutton->isToggleButton();
+}
+
+void KButton_impl::toggle(bool newToggle)
+{
+ _qpushbutton->setToggleButton(newToggle);
+}
+
+bool KButton_impl::pressed()
+{
+ if( _qpushbutton->isToggleButton() )
+ return _qpushbutton->isOn();
+ else
+ return _qpushbutton->isDown();
+}
+
+bool KButton_impl::clicked()
+{
+ if( _clicked )
+ {
+ _clicked = false;
+ return true;
+ }
+ return false;
+}
+
+void KButton_impl::changeState(bool newState)
+{
+ pressed_changed(newState);
+}
+
+REGISTER_IMPLEMENTATION(KButton_impl);
+
+// vim:sw=4:ts=4
diff --git a/arts/gui/kde/kbutton_impl.h b/arts/gui/kde/kbutton_impl.h
new file mode 100644
index 00000000..2c3c7163
--- /dev/null
+++ b/arts/gui/kde/kbutton_impl.h
@@ -0,0 +1,76 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 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 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.
+
+ */
+
+#ifndef ARTS_GUI_KBUTTON_IMPL_H
+#define ARTS_GUI_KBUTTON_IMPL_H
+#include "kwidget_impl.h"
+#include <qpushbutton.h>
+
+
+namespace Arts {
+class KButton_impl;
+class KButtonMapper : public QObject {
+ Q_OBJECT
+ KButton_impl *impl;
+ QPushButton * button;
+public:
+ KButtonMapper(KButton_impl *impl, QPushButton *but);
+protected slots:
+ void pressed();
+ void released();
+ void toggled( bool );
+ void clicked();
+};
+
+class KButton_impl : virtual public Arts::Button_skel,
+ public Arts::KWidget_impl
+{
+private:
+ bool _clicked;
+
+protected:
+ QPushButton * _qpushbutton;
+
+public:
+ KButton_impl( QPushButton * w = 0 );
+ void constructor( Widget parent );
+ void constructor( const std::string &, Widget );
+
+ void emitClicked();
+
+ std::string text();
+ void text(const std::string& newCaption);
+
+ bool toggle();
+ void toggle(bool);
+
+ bool pressed();
+ bool clicked();
+ void changeState(bool);
+};
+
+}
+#endif //ARTS_GUI_KBUTTON_IMPL_H
+
+// vim:sw=4:ts=4
diff --git a/arts/gui/kde/kcombobox_impl.cpp b/arts/gui/kde/kcombobox_impl.cpp
new file mode 100644
index 00000000..dfa4e637
--- /dev/null
+++ b/arts/gui/kde/kcombobox_impl.cpp
@@ -0,0 +1,105 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 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 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 "kcombobox_impl.h"
+#include "kcombobox_impl.moc"
+#include "anyref.h"
+#include "stdio.h"
+
+using namespace Arts;
+using namespace std;
+
+ComboBoxIntMapper::ComboBoxIntMapper(KComboBox_impl *impl, KComboBox *co)
+ : QObject( co, "map Qt signal to aRts" )
+ ,impl(impl)
+{
+ connect(co, SIGNAL(activated(const QString &)), this, SLOT(activated(const QString &)));
+}
+
+void ComboBoxIntMapper::activated(const QString & newValue)
+{
+ impl->value(string(newValue.utf8().data()));
+}
+
+KComboBox_impl::KComboBox_impl( KComboBox * widget )
+ : KWidget_impl( widget ? widget : new KComboBox )
+{
+ _kcombobox = static_cast<KComboBox*>( _qwidget );
+ ( void )new ComboBoxIntMapper( this, _kcombobox );
+}
+
+string KComboBox_impl::caption()
+{
+ return m_caption.utf8().data();
+}
+
+void KComboBox_impl::caption(const string& newCaption)
+{
+ m_caption = QString::fromUtf8(newCaption.c_str());
+ // FIXME: do something with the caption here
+}
+
+vector<string> * KComboBox_impl::choices()
+{
+ return new vector<string>(m_choices);
+}
+
+void KComboBox_impl::choices(const vector<string> & newChoices)
+{
+ if(newChoices != m_choices)
+ {
+ m_choices = newChoices;
+ _kcombobox->clear();
+ for(vector<string>::const_iterator it = m_choices.begin(); it != m_choices.end(); ++it)
+ {
+ _kcombobox->insertItem(QString::fromUtf8(it->c_str()));
+ }
+ if(visible())
+ choices_changed(newChoices);
+ }
+}
+
+string KComboBox_impl::value()
+{
+ return m_value.utf8().data();
+}
+
+void KComboBox_impl::value(const string & newValue)
+{
+ if(newValue != m_value.utf8().data())
+ {
+ m_value = QString::fromUtf8(newValue.c_str());
+ for(unsigned int i = 0; i < m_choices.size(); ++i)
+ {
+ if(m_choices[i] == newValue)
+ _kcombobox->setCurrentItem(i);
+ }
+ if(visible())
+ value_changed(newValue);
+ }
+}
+
+REGISTER_IMPLEMENTATION(KComboBox_impl);
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kcombobox_impl.h b/arts/gui/kde/kcombobox_impl.h
new file mode 100644
index 00000000..83222e3b
--- /dev/null
+++ b/arts/gui/kde/kcombobox_impl.h
@@ -0,0 +1,74 @@
+ /*
+
+ Copyright (C) 2000,2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 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 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.
+
+ */
+
+#ifndef ARTS_GUI_KCOMBOBOX_IMPL_H
+#define ARTS_GUI_KCOMBOBOX_IMPL_H
+#include "kwidget_impl.h"
+#include <kcombobox.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+
+namespace Arts {
+
+class KComboBox_impl;
+class ComboBoxIntMapper :public QObject {
+ Q_OBJECT
+ KComboBox_impl *impl;
+public:
+ ComboBoxIntMapper(KComboBox_impl *impl, KComboBox *co);
+public slots:
+ void activated(const QString &);
+};
+
+class KComboBox_impl : virtual public Arts::ComboBox_skel,
+ public Arts::KWidget_impl
+{
+protected:
+ KComboBox * _kcombobox;
+ QString m_caption;
+ QString m_value;
+ std::vector<std::string> m_choices;
+
+ void applyValue();
+
+public:
+ KComboBox_impl( KComboBox * w = 0 );
+ void constructor( Widget p ) { parent( p ); }
+
+ std::string caption();
+ void caption(const std::string & newCaption);
+
+ std::vector<std::string> * choices();
+ void choices(const std::vector<std::string> & newChoices);
+
+ std::string value();
+ void value(const std::string & newValue);
+};
+
+}
+#endif /* ARTS_GUI_KCOMBOBOX_IMPL_H */
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kfader.cpp b/arts/gui/kde/kfader.cpp
new file mode 100644
index 00000000..2978dd0c
--- /dev/null
+++ b/arts/gui/kde/kfader.cpp
@@ -0,0 +1,31 @@
+#include "kfader.h"
+#include "kfader.moc"
+
+void KFader::init()
+{
+}
+
+KFader::KFader( QWidget * parent, const char * name )
+ : QSlider( Qt::Vertical, parent, name )
+{
+ init();
+}
+
+KFader::KFader( int minValue, int maxValue, int pageStep, int value, QWidget * parent, const char * name )
+ : QSlider( minValue, maxValue, pageStep, value, Qt::Vertical, parent, name )
+{
+ init();
+}
+
+KFader::~KFader()
+{
+}
+
+void KFader::setColor( QColor & )
+{
+}
+
+void KFader::setRange( int minValue, int maxValue )
+{
+ QRangeControl::setRange( minValue, maxValue );
+}
diff --git a/arts/gui/kde/kfader.h b/arts/gui/kde/kfader.h
new file mode 100644
index 00000000..fcf53f21
--- /dev/null
+++ b/arts/gui/kde/kfader.h
@@ -0,0 +1,46 @@
+ /*
+
+ Copyright (C) 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.
+
+ */
+
+#ifndef _KFADER_H
+#define _KFADER_H
+
+#include <qslider.h>
+
+class KFader : public QSlider
+{
+ Q_OBJECT
+ protected:
+ void init();
+ public:
+ KFader( QWidget * parent = 0, const char * name = 0 );
+ KFader( int minValue, int maxValue, int pageStep, int value, QWidget * parent = 0, const char * name = 0 );
+
+ virtual ~KFader();
+
+ void setColor( QColor & );
+
+ virtual void setRange( int, int );
+};
+
+#endif /* KFADER_H */
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kfader_impl.cpp b/arts/gui/kde/kfader_impl.cpp
new file mode 100644
index 00000000..3304f3d3
--- /dev/null
+++ b/arts/gui/kde/kfader_impl.cpp
@@ -0,0 +1,206 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 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 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 "kfader_impl.h"
+#include "kfader_impl.moc"
+#include "anyref.h"
+#include "stdio.h"
+
+#include <math.h>
+
+using namespace Arts;
+using namespace std;
+
+FaderIntMapper::FaderIntMapper(KFader_impl *impl, KFader *kp) :impl(impl)
+{
+ connect(kp, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
+}
+
+void FaderIntMapper::valueChanged(int pos)
+{
+ impl->valueChanged(pos);
+}
+
+KFader_impl::KFader_impl( KFader * widget )
+ : KWidget_impl( widget ? widget : new KFader( 0, 100, 1, 0 ) )
+{
+ _min = 0; _max = 1; _value = 0;
+ _factor = 1;
+ _logarithmic = 0;
+ _range = 100;
+
+ _kfader = static_cast<KFader*>( _qwidget );
+ _kfader->setMinimumWidth( 40 );
+ _kfader->setMinimumHeight( 100 );
+ new FaderIntMapper( this, _kfader );
+}
+
+string KFader_impl::caption()
+{
+ return _caption.utf8().data();
+}
+
+void KFader_impl::caption(const string& newText)
+{
+ _caption = QString::fromUtf8(newText.c_str());
+ _kfader->setName(_caption.utf8().data());
+}
+
+string KFader_impl::color()
+{
+ return _color;
+}
+
+void KFader_impl::color(const string& newColor)
+{
+ _color = newColor;
+ if(strlen(_color.c_str()))
+ {
+ QColor qc(_color.c_str());
+ _kfader->setColor(qc);
+ }
+}
+
+float KFader_impl::min()
+{
+ return _min;
+}
+
+void KFader_impl::min(float newMin)
+{
+ if(_min != newMin)
+ {
+ _min = newMin;
+ applyValue();
+ }
+}
+
+float KFader_impl::max()
+{
+ return _max;
+}
+
+void KFader_impl::max(float newMax)
+{
+ if(_max != newMax)
+ {
+ _max = newMax;
+ applyValue();
+ }
+}
+
+float KFader_impl::value()
+{
+ //float ret = ( _max + _min - float(_kfader->value()) ) / _factor;
+ //if(_logarithmic > 0)
+ //ret = convertFromLog(ret);
+ float ret = _value;
+ if(ret < _min)
+ ret = _min;
+ else if(ret > _max)
+ ret = _max;
+ return ret;
+}
+
+void KFader_impl::value(float newValue)
+{
+ if(newValue != _value)
+ {
+ _value = newValue;
+ applyValue();
+ if(visible())
+ value_changed(value());
+ }
+}
+
+long KFader_impl::range()
+{
+ return _range;
+}
+
+void KFader_impl::range(long newRange)
+{
+ if(_range != newRange)
+ {
+ _range = newRange;
+ applyValue();
+ }
+}
+
+void KFader_impl::valueChanged(int newvalue)
+{
+ _value = float(newvalue) / _factor;
+ if(_logarithmic > 0)
+ _value = convertFromLog(_value);
+ _value = _max + _min - _value;
+ if(visible())
+ value_changed(value());
+}
+
+float KFader_impl::convertToLog(float val)
+{
+ return log(val) / log(_logarithmic);
+}
+
+float KFader_impl::convertFromLog(float val)
+{
+ return pow(_logarithmic, val);
+}
+
+void KFader_impl::applyValue()
+{
+ double dmin = _min;
+ double dmax = _max;
+ double dvalue = _value;
+ if(_logarithmic > 0)
+ {
+ dmin = convertToLog(_min);
+ dmax = convertToLog(_max);
+ dvalue = convertToLog(_value);
+ }
+ _factor = _range / (dmax - dmin);
+ int imin = int(_factor * dmin);
+ int imax = int(_factor * dmax);
+ int ivalue = int(_factor * (dmax + dmin - dvalue));
+ _kfader->setRange(imin, imax);
+ _kfader->setValue(ivalue);
+}
+
+void KFader_impl::logarithmic(float newLogarithmic)
+{
+ if(_logarithmic != newLogarithmic)
+ {
+ _logarithmic = newLogarithmic;
+ applyValue();
+ }
+}
+
+float KFader_impl::logarithmic()
+{
+ return _logarithmic;
+}
+
+REGISTER_IMPLEMENTATION(KFader_impl);
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kfader_impl.h b/arts/gui/kde/kfader_impl.h
new file mode 100644
index 00000000..55419cff
--- /dev/null
+++ b/arts/gui/kde/kfader_impl.h
@@ -0,0 +1,92 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 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 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.
+
+ */
+
+#ifndef ARTS_GUI_KFADER_IMPL_H
+#define ARTS_GUI_KFADER_IMPL_H
+#include "kwidget_impl.h"
+#include "kfader.h"
+
+#include <qobject.h>
+#include <qstring.h>
+
+
+namespace Arts {
+
+class KFader_impl;
+
+class FaderIntMapper :public QObject {
+ Q_OBJECT
+ KFader_impl *impl;
+public:
+ FaderIntMapper(KFader_impl *impl, KFader *kp);
+public slots:
+ void valueChanged(int x);
+};
+
+class KFader_impl : virtual public Arts::Fader_skel,
+ public Arts::KWidget_impl
+{
+protected:
+ KFader * _kfader;
+ QString _caption;
+ std::string _color;
+ float _min, _max, _value;
+ float _factor;
+ float _logarithmic;
+ long _range;
+
+ float convertToLog(float);
+ float convertFromLog(float);
+ void applyValue();
+
+public:
+ KFader_impl( KFader * w = 0 );
+ void constructor( Widget p ) { parent( p ); }
+
+ std::string caption();
+ void caption(const std::string& newText);
+ std::string color();
+ void color(const std::string& newColor);
+
+ float logarithmic();
+ void logarithmic(float);
+
+ float min();
+ void min(float newMin);
+ float max();
+ void max(float newMax);
+ float value();
+ void value(float newValue);
+
+ long range();
+ void range(long newRange);
+
+ /* from qt */
+ void valueChanged(int newValue);
+};
+
+}
+#endif /* ARTS_GUI_KFADER_IMPL_H */
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kframe_impl.cpp b/arts/gui/kde/kframe_impl.cpp
new file mode 100644
index 00000000..a2fc6d8c
--- /dev/null
+++ b/arts/gui/kde/kframe_impl.cpp
@@ -0,0 +1,98 @@
+/*
+ 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 "kframe_impl.h"
+#include <qframe.h>
+#include <debug.h>
+#include <stdio.h>
+
+using namespace Arts;
+using namespace std;
+
+KFrame_impl::KFrame_impl( QFrame * widget )
+ : KWidget_impl( widget ? widget : new QFrame )
+{
+ _qframe = static_cast<QFrame*>( _qwidget );
+ assert( _qframe );
+}
+
+long KFrame_impl::margin()
+{
+ return _qframe->margin();
+}
+
+void KFrame_impl::margin( long m )
+{
+ _qframe->setMargin( m );
+}
+
+long KFrame_impl::linewidth()
+{
+ return _qframe->lineWidth();
+}
+
+void KFrame_impl::linewidth( long lw )
+{
+ _qframe->setLineWidth( lw );
+}
+
+long KFrame_impl::midlinewidth()
+{
+ return _qframe->midLineWidth();
+}
+
+void KFrame_impl::midlinewidth( long mlw )
+{
+ _qframe->setMidLineWidth( mlw );
+}
+
+long KFrame_impl::framestyle()
+{
+ return _qframe->frameStyle();
+}
+
+void KFrame_impl::framestyle( long fs )
+{
+ _qframe->setFrameStyle( fs );
+}
+
+Shape KFrame_impl::frameshape()
+{
+ return ( Shape )_qframe->frameShape();
+}
+
+void KFrame_impl::frameshape( Shape fs )
+{
+ _qframe->setFrameShape( ( QFrame::Shape )fs );
+}
+
+Shadow KFrame_impl::frameshadow()
+{
+ return ( Shadow )_qframe->frameShadow();
+}
+
+void KFrame_impl::frameshadow( Shadow fs )
+{
+ _qframe->setFrameShadow( ( QFrame::Shadow )fs );
+}
+
+REGISTER_IMPLEMENTATION(KFrame_impl);
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kframe_impl.h b/arts/gui/kde/kframe_impl.h
new file mode 100644
index 00000000..3b4bcb69
--- /dev/null
+++ b/arts/gui/kde/kframe_impl.h
@@ -0,0 +1,55 @@
+/*
+ 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$
+
+#ifndef KFRAME_IMPL
+#define KFRAME_IMPL
+#include "kwidget_impl.h"
+#include <kdelibs_export.h>
+class QFrame;
+
+namespace Arts {
+
+class KDE_EXPORT KFrame_impl : virtual public Arts::Frame_skel,
+ public Arts::KWidget_impl
+{
+ protected:
+ QFrame * _qframe;
+
+ public:
+ KFrame_impl( QFrame * widget = 0 );
+ inline void constructor( Widget p ) { parent( p ); }
+
+ long margin();
+ void margin( long m );
+ long linewidth();
+ void linewidth( long lw );
+ long midlinewidth();
+ void midlinewidth( long mlw );
+ long framestyle();
+ void framestyle( long fs );
+ Shape frameshape();
+ void frameshape( Shape fs );
+ Shadow frameshadow();
+ void frameshadow( Shadow fs );
+}; //class
+} //namespace
+
+// vim: sw=4 ts=4
+#endif
diff --git a/arts/gui/kde/kgraph.cpp b/arts/gui/kde/kgraph.cpp
new file mode 100644
index 00000000..e7797692
--- /dev/null
+++ b/arts/gui/kde/kgraph.cpp
@@ -0,0 +1,266 @@
+ /*
+
+ 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 "kgraph.h"
+#include "kgraph.moc"
+#include "kgraphline_impl.h"
+#include "qpainter.h"
+
+#include <cstdlib>
+#include <math.h>
+
+using namespace Arts;
+using namespace std;
+
+KGraph::KGraph( QWidget * parent, const char * name )
+ : QWidget( parent, name )
+{
+ setBackgroundColor(white);
+
+ selectedIndex = -1;
+ minx = miny = 0.0;
+ maxx = maxy = 1.0;
+}
+
+KGraph::~KGraph()
+{
+}
+
+void KGraph::addLine(Arts::KGraphLine_impl *line)
+{
+ lines.push_back(line);
+}
+
+void KGraph::redrawLine(Arts::KGraphLine_impl * /*line*/)
+{
+ repaint();
+}
+
+void KGraph::removeLine(Arts::KGraphLine_impl *line)
+{
+ if(line == selectedLine)
+ {
+ selectedLine = 0;
+ selectedIndex = -1;
+ }
+ lines.remove(line);
+}
+
+inline QPoint KGraph::g2qPoint(const GraphPoint &gp)
+{
+ return QPoint(int(((gp.x - minx)/(maxx-minx)) * (width()-1)),
+ int((1.0 - (gp.y - miny)/(maxy-miny)) * (height()-1)));
+}
+
+inline GraphPoint KGraph::q2gPoint(const QPoint &qp)
+{
+ return GraphPoint((float(qp.x())/float(width()-1)) * (maxx-minx) + minx,
+ (1.0 - (float(qp.y())/float(height()-1))) * (maxy-miny) + miny);
+}
+
+void KGraph::paintEvent( QPaintEvent *e )
+{
+ QPainter painter(this);
+ painter.setClipRect(e->rect());
+
+ std::list<KGraphLine_impl *>::iterator li;
+ for(li = lines.begin(); li != lines.end(); li++)
+ {
+ KGraphLine_impl *gline = *li;
+
+ vector<GraphPoint>::iterator pi;
+ QPoint lastp;
+ bool first = true;
+
+ painter.setPen(gline->_color.c_str());
+
+ for(pi = gline->_points.begin(); pi != gline->_points.end(); pi++)
+ {
+ QPoint p = g2qPoint(*pi);
+
+ if(!first)
+ painter.drawLine(lastp,p);
+
+ if(gline->_editable)
+ painter.drawEllipse(p.x()-3,p.y()-3,7,7);
+
+ lastp = p;
+ first = false;
+ }
+ }
+}
+
+void KGraph::mousePressEvent(QMouseEvent *e)
+{
+ if(e->button() == LeftButton || e->button() == RightButton)
+ {
+ std::list<KGraphLine_impl *>::iterator li;
+ for(li = lines.begin(); li != lines.end(); li++)
+ {
+ KGraphLine_impl *gline = *li;
+
+ vector<GraphPoint>::iterator pi;
+ int index = 0;
+ for(pi = gline->_points.begin(); pi != gline->_points.end(); pi++, index++)
+ {
+ QPoint p = g2qPoint(*pi);
+
+ int dx = e->x() - p.x();
+ int dy = e->y() - p.y();
+
+ if(::sqrt(double(dx*dx + dy*dy)) < 5.0)
+ {
+ selectedIndex = index;
+ selectedLine = gline;
+ selectedPoint = *pi;
+ }
+ }
+ }
+ }
+
+ if(selectedIndex >= 0)
+ {
+ // erase point
+ if(e->button() == RightButton)
+ {
+ if(selectedIndex != 0 && selectedIndex != (( int )( selectedLine->_points.size() )-1))
+ {
+ vector<GraphPoint> points;
+
+ for(int i=0;i<( int )selectedLine->_points.size();i++)
+ {
+ if(selectedIndex != i)
+ points.push_back(selectedLine->_points[i]);
+ }
+
+ selectedLine->points(points);
+ }
+
+ selectedLine = 0;
+ selectedIndex = -1;
+ }
+ }
+ else if(e->button() == LeftButton)
+ {
+ // try to insert a point
+ std::list<KGraphLine_impl *>::iterator li;
+ for(li = lines.begin(); li != lines.end(); li++)
+ {
+ KGraphLine_impl *gline = *li;
+
+ QPoint lastp;
+ bool first = true;
+
+ vector<GraphPoint>::iterator pi;
+ int index = 0;
+ for(pi = gline->_points.begin(); pi != gline->_points.end(); pi++, index++)
+ {
+ QPoint p = g2qPoint(*pi);
+
+ if(!first && (e->x() > lastp.x()+2) && (e->x() < p.x()-2))
+ {
+ float pos = float(e->x()-lastp.x())/float(p.x()-lastp.x());
+ int y = (int)((1.0-pos) * lastp.y() + pos * p.y());
+
+ if(abs(y-e->y()) < 5)
+ {
+ GraphPoint gp = q2gPoint(QPoint(e->x(),y));
+ vector<GraphPoint> newPoints;
+
+ for(int i=0;i<( int )gline->_points.size();i++)
+ {
+ if(index == i)
+ newPoints.push_back(gp);
+ newPoints.push_back(gline->_points[i]);
+ }
+ gline->points(newPoints);
+
+ selectedLine = gline;
+ selectedIndex = index;
+ selectedPoint = gp;
+
+ return;
+ }
+ }
+ lastp = p;
+ first = false;
+ }
+ }
+ }
+}
+
+void KGraph::mouseMoveEvent(QMouseEvent *e)
+{
+ QPoint pos = e->pos();
+
+ if(pos.x() < 0) pos.setX(0);
+ if(pos.y() < 0) pos.setY(0);
+ if(pos.x() >= width()) pos.setX(width()-1);
+ if(pos.y() >= height()) pos.setY(height()-1);
+
+ if(selectedIndex >= 0)
+ {
+ vector<GraphPoint> points(selectedLine->_points);
+
+
+ if((( int )points.size() <= selectedIndex)
+ || (fabs(selectedPoint.x-points[selectedIndex].x) > 0.000001)
+ || (fabs(selectedPoint.y-points[selectedIndex].y) > 0.000001))
+ {
+ selectedLine = 0;
+ selectedIndex = -1;
+ return; // line was modified from somewhere else, meanwhile
+ }
+
+ // I am not sure whether we always want to constrain it that way
+ GraphPoint gp = q2gPoint(pos);
+ selectedPoint.y = gp.y;
+
+ if(selectedIndex != 0 && selectedIndex != (( int )( points.size() )-1))
+ {
+ float pixelsize = (maxx-minx)/float(width()-1);
+
+ if(selectedIndex > 0 && points[selectedIndex-1].x > gp.x)
+ {
+ selectedPoint.x = points[selectedIndex-1].x+pixelsize;
+ }
+ else if(selectedIndex < (( int )( points.size() )-1) && points[selectedIndex+1].x < gp.x)
+ {
+ selectedPoint.x = points[selectedIndex+1].x-pixelsize;
+ }
+ else
+ {
+ selectedPoint.x = gp.x;
+ }
+ }
+ points[selectedIndex] = selectedPoint;
+ selectedLine->points(points);
+ }
+}
+
+void KGraph::mouseReleaseEvent(QMouseEvent *)
+{
+ selectedIndex = -1;
+ selectedLine = 0;
+}
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kgraph.h b/arts/gui/kde/kgraph.h
new file mode 100644
index 00000000..51e64d70
--- /dev/null
+++ b/arts/gui/kde/kgraph.h
@@ -0,0 +1,64 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef _KGRAPH_H
+#define _KGRAPH_H
+
+#include <qwidget.h>
+#include <qpoint.h>
+#include "artsgui.h"
+#include <list>
+
+namespace Arts {
+
+class KGraphLine_impl;
+class KGraph : public QWidget
+{
+Q_OBJECT
+
+protected:
+ std::list<KGraphLine_impl *> lines;
+ float minx, maxx, miny, maxy;
+
+ KGraphLine_impl *selectedLine;
+ GraphPoint selectedPoint;
+ int selectedIndex; // -1 if nothing is selected
+
+ inline GraphPoint q2gPoint(const QPoint &qp);
+ inline QPoint g2qPoint(const GraphPoint &gp);
+public:
+ KGraph( QWidget * parent = 0, const char * name = 0 );
+ virtual ~KGraph();
+
+ void addLine(Arts::KGraphLine_impl *line);
+ void redrawLine(Arts::KGraphLine_impl *line);
+ void removeLine(Arts::KGraphLine_impl *line);
+
+ void mousePressEvent(QMouseEvent *me);
+ void mouseMoveEvent(QMouseEvent *me);
+ void mouseReleaseEvent(QMouseEvent *me);
+
+ void paintEvent(QPaintEvent *e);
+};
+}
+
+#endif /* KGRAPH_H */
diff --git a/arts/gui/kde/kgraph_impl.cpp b/arts/gui/kde/kgraph_impl.cpp
new file mode 100644
index 00000000..f629e680
--- /dev/null
+++ b/arts/gui/kde/kgraph_impl.cpp
@@ -0,0 +1,92 @@
+ /*
+
+ Copyright (C) 2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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 "kgraph_impl.h"
+#include "anyref.h"
+#include "stdio.h"
+
+using namespace Arts;
+using namespace std;
+
+KGraph_impl::KGraph_impl( KGraph * widget )
+ : KWidget_impl( widget ? widget : new KGraph )
+{
+ _minx = 0.0; _maxx = 1.0; _miny = 0.0; _maxy = 1.0;
+ _kgraph = static_cast<KGraph*>( _qwidget );
+ _kgraph->setFixedSize( 300, 200 );
+}
+
+string KGraph_impl::caption()
+{
+ return _caption.utf8().data();
+}
+
+void KGraph_impl::caption(const string& newCaption)
+{
+ _caption = QString::fromUtf8(newCaption.c_str());
+ // FIXME: do something with the caption here
+}
+
+float KGraph_impl::minx()
+{
+ return _minx;
+}
+
+void KGraph_impl::minx(float newMin)
+{
+ _minx = newMin;
+}
+
+float KGraph_impl::maxx()
+{
+ return _maxx;
+}
+
+void KGraph_impl::maxx(float newMax)
+{
+ _maxx = newMax;
+}
+
+float KGraph_impl::miny()
+{
+ return _miny;
+}
+
+void KGraph_impl::miny(float newMin)
+{
+ _miny = newMin;
+}
+
+float KGraph_impl::maxy()
+{
+ return _maxy;
+}
+
+void KGraph_impl::maxy(float newMax)
+{
+ _maxy = newMax;
+}
+
+namespace Arts { REGISTER_IMPLEMENTATION(KGraph_impl); }
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kgraph_impl.h b/arts/gui/kde/kgraph_impl.h
new file mode 100644
index 00000000..b576d65a
--- /dev/null
+++ b/arts/gui/kde/kgraph_impl.h
@@ -0,0 +1,65 @@
+ /*
+
+ Copyright (C) 2000,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.
+
+ */
+
+#ifndef ARTS_GUI_KGRAPH_IMPL_H
+#define ARTS_GUI_KGRAPH_IMPL_H
+#include "kwidget_impl.h"
+#include "kgraph.h"
+
+#include <qobject.h>
+#include <qstring.h>
+
+
+namespace Arts {
+
+class KGraph_impl;
+
+class KGraph_impl : virtual public Arts::Graph_skel,
+ public Arts::KWidget_impl
+{
+protected:
+ QString _caption;
+ float _minx, _miny, _maxx, _maxy;
+
+ KGraph * _kgraph;
+
+public:
+ KGraph_impl( KGraph * w = 0 );
+ void constructor( Widget p ) { parent( p ); }
+
+ std::string caption();
+ void caption(const std::string& newCaption);
+
+ float minx();
+ void minx(float newMin);
+ float maxx();
+ void maxx(float newMax);
+ float miny();
+ void miny(float newMin);
+ float maxy();
+ void maxy(float newMax);
+};
+
+}
+#endif /* ARTS_GUI_KGRAPH_IMPL_H */
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kgraphline_impl.cpp b/arts/gui/kde/kgraphline_impl.cpp
new file mode 100644
index 00000000..5a48c000
--- /dev/null
+++ b/arts/gui/kde/kgraphline_impl.cpp
@@ -0,0 +1,124 @@
+ /*
+
+ 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 "kgraphline_impl.h"
+#include "kwidgetrepo.h"
+#include "kgraph.h"
+
+using namespace Arts;
+using namespace std;
+
+KGraphLine_impl::KGraphLine_impl()
+{
+ _graphID = -1;
+}
+
+KGraphLine_impl::~KGraphLine_impl()
+{
+ KGraph *kgraph = getKGraph();
+ if(kgraph)
+ kgraph->removeLine(this);
+}
+
+Graph KGraphLine_impl::graph()
+{
+ return Arts::DynamicCast(KWidgetRepo::the()->lookupWidget(_graphID));
+}
+
+void KGraphLine_impl::graph(Graph newGraph)
+{
+ KGraph *kgraph = getKGraph();
+ if(kgraph)
+ kgraph->removeLine(this);
+
+ _graphID = newGraph.widgetID();
+
+ kgraph = getKGraph();
+ if(kgraph)
+ kgraph->addLine(this);
+}
+
+bool KGraphLine_impl::editable()
+{
+ return _editable;
+}
+
+void KGraphLine_impl::editable(bool newEditable)
+{
+ _editable = newEditable;
+
+ KGraph *kgraph = getKGraph();
+ if(kgraph)
+ kgraph->redrawLine(this);
+}
+
+string KGraphLine_impl::color()
+{
+ return _color;
+}
+
+void KGraphLine_impl::color(const std::string& newColor)
+{
+ _color = newColor;
+
+ KGraph *kgraph = getKGraph();
+ if(kgraph)
+ kgraph->redrawLine(this);
+}
+
+vector<GraphPoint> *KGraphLine_impl::points()
+{
+ return new vector<GraphPoint>(_points);
+}
+
+void KGraphLine_impl::points(const vector<GraphPoint>& newPoints)
+{
+ _points = newPoints;
+
+ KGraph *kgraph = getKGraph();
+ if(kgraph)
+ kgraph->redrawLine(this);
+
+ // emitting a change notification is a bit tricky because no real
+ // Arts::AnyRef support is there for sequence<Arts::GraphPoint>
+ Arts::Any any;
+ Arts::Buffer buffer;
+
+ any.type = "*Arts::GraphPoint";
+ writeTypeSeq(buffer,_points);
+ buffer.read(any.value,buffer.size());
+
+ _emit_changed("points_changed",any);
+}
+
+KGraph *KGraphLine_impl::getKGraph()
+{
+ QWidget *widget = KWidgetRepo::the()->lookupQWidget(_graphID);
+ if(!widget)
+ return 0;
+
+ return dynamic_cast<KGraph *>(widget);
+}
+
+namespace Arts {
+ REGISTER_IMPLEMENTATION(KGraphLine_impl);
+}
diff --git a/arts/gui/kde/kgraphline_impl.h b/arts/gui/kde/kgraphline_impl.h
new file mode 100644
index 00000000..546cff90
--- /dev/null
+++ b/arts/gui/kde/kgraphline_impl.h
@@ -0,0 +1,61 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef _KGRAPHLINE_IMPL_H
+#define _KGRAPHLINE_IMPL_H
+
+#include "artsgui.h"
+
+namespace Arts {
+
+class KGraph;
+class KGraphLine_impl : virtual public GraphLine_skel {
+protected:
+ friend class KGraph; // for efficiency
+
+ long _graphID;
+ bool _editable;
+ std::string _color;
+ std::vector<GraphPoint> _points;
+
+ KGraph *getKGraph();
+
+public:
+ KGraphLine_impl();
+ ~KGraphLine_impl();
+
+ Graph graph();
+ void graph(Graph newGraph);
+
+ bool editable();
+ void editable(bool newEditable);
+
+ std::string color();
+ void color(const std::string& newColor);
+
+ std::vector<GraphPoint> *points();
+ void points(const std::vector<GraphPoint>& newPoints);
+};
+
+}
+
+#endif /* _KGRAPHLINE_IMPL_H */
diff --git a/arts/gui/kde/khbox_impl.cpp b/arts/gui/kde/khbox_impl.cpp
new file mode 100644
index 00000000..90ed9a3b
--- /dev/null
+++ b/arts/gui/kde/khbox_impl.cpp
@@ -0,0 +1,51 @@
+ /*
+
+ Copyright (C) 2000,2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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 "khbox_impl.h"
+#include <qhbox.h>
+
+using namespace Arts;
+
+KHBox_impl::KHBox_impl( QHBox * widget )
+ : KFrame_impl( widget ? widget : new QHBox )
+ , _spacing( 5 )
+{
+ _qhbox = static_cast<QHBox*>( _qwidget );
+ _qhbox->setSpacing( _spacing );
+ _qhbox->setMargin( 5 );
+}
+
+long KHBox_impl::spacing()
+{
+ return _spacing;
+}
+
+void KHBox_impl::spacing( long s )
+{
+ _spacing = s;
+ _qhbox->setSpacing( s );
+}
+
+REGISTER_IMPLEMENTATION(KHBox_impl);
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/khbox_impl.h b/arts/gui/kde/khbox_impl.h
new file mode 100644
index 00000000..70bade71
--- /dev/null
+++ b/arts/gui/kde/khbox_impl.h
@@ -0,0 +1,48 @@
+ /*
+
+ Copyright (C) 2000,2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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 "kframe_impl.h"
+
+class QHBox;
+
+namespace Arts {
+
+class KHBox_impl : virtual public Arts::HBox_skel,
+ public Arts::KFrame_impl
+{
+private:
+ long _spacing;
+
+protected:
+ QHBox * _qhbox;
+
+public:
+ KHBox_impl( QHBox * w = 0 );
+
+ long spacing();
+ void spacing( long );
+};
+
+}
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klabel_impl.cpp b/arts/gui/kde/klabel_impl.cpp
new file mode 100644
index 00000000..f53de2e7
--- /dev/null
+++ b/arts/gui/kde/klabel_impl.cpp
@@ -0,0 +1,104 @@
+/*
+ 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 "klabel_impl.h"
+#include "klabel_impl.moc"
+
+#include <kdebug.h>
+#include <qfont.h>
+
+using namespace Arts;
+using namespace std;
+
+KLabel_impl::KLabel_impl( QFrame *widget ) : KFrame_impl( widget ? widget : new RotateLabel( 0 ) ) {
+ _label = static_cast<RotateLabel*>( _qwidget );
+}
+
+string KLabel_impl::text() {
+ return _label->title().utf8().data();
+}
+
+void KLabel_impl::text( const string& newtext ) {
+ _label->title( QString::fromUtf8( newtext.c_str() ) );
+}
+
+long KLabel_impl::align() { return _label->align(); }
+void KLabel_impl::align( long n ) { _label->align( n ); }
+
+void KLabel_impl::fontsize( long n ) { _label->fontsize( n ); }
+void KLabel_impl::fontfamily( const std::string& n ) { _label->fontfamily( n.c_str() ); }
+
+Arts::TextBottom KLabel_impl::bottom() { return _label->bottom(); }
+void KLabel_impl::bottom( Arts::TextBottom n ) { _label->bottom( n ); }
+
+REGISTER_IMPLEMENTATION( KLabel_impl );
+
+RotateLabel::RotateLabel( QWidget* p, const char* n ) : QFrame( p,n ) {
+ _bottom = Arts::South;
+ _align = Arts::AlignCenter;
+}
+void RotateLabel::paintEvent( QPaintEvent* ) {
+ QPainter p( this );
+ if ( _bottom == Arts::East ) {
+ p.rotate( 270 );
+ p.drawText( QRect( 0,0, -height(), width() ), _align, _title );
+ } else if ( _bottom == Arts::West ) {
+ p.rotate( 90 );
+ p.drawText( QRect( 0,0, height(), -width() ), _align, _title );
+ } else if ( _bottom == Arts::North ) {
+ p.rotate( 180 );
+ p.drawText( QRect( 0,0, -width(), -height() ), _align, _title );
+ } else {
+ p.drawText( QRect( 0,0, width(), height() ), _align, _title );
+ }
+}
+
+void RotateLabel::fontfamily( QString n ) {
+ QFont font = this->font();
+ font.setFamily( n );
+ this->setFont( font );
+}
+void RotateLabel::fontsize( int n ) {
+ QFont font = this->font();
+ font.setPixelSize( n );
+ this->setFont( font );
+}
+
+void RotateLabel::title( QString n ) {
+ _title = n;
+ QSize size = this->fontMetrics().size( SingleLine, _title );
+ if ( _bottom == Arts::East || _bottom == Arts::West )
+ this->setMinimumSize( size.height(), size.width() );
+ else
+ this->setMinimumSize( size );
+}
+
+void RotateLabel::align( long n ) {
+ _align=n;
+ repaint();
+}
+
+void RotateLabel::bottom( Arts::TextBottom bottom ) {
+ _bottom = bottom;
+ title( _title );
+ repaint();
+}
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klabel_impl.h b/arts/gui/kde/klabel_impl.h
new file mode 100644
index 00000000..62b505a3
--- /dev/null
+++ b/arts/gui/kde/klabel_impl.h
@@ -0,0 +1,90 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef ARTS_KLABEL_IMPL
+#define ARTS_KLABEL_IMPL
+
+#include <kframe_impl.h>
+#include <qframe.h>
+#include <qpainter.h>
+#include <qfontmetrics.h>
+#include <qfont.h>
+
+#include <artsgui.h>
+#include <kdelibs_export.h>
+
+class RotateLabel;
+
+namespace Arts {
+
+class KDE_EXPORT KLabel_impl : virtual public Arts::Label_skel,
+ public Arts::KFrame_impl
+{
+protected:
+ RotateLabel* _label;
+public:
+ KLabel_impl( QFrame* w=0 );
+ void constructor( Widget p ) { parent( p ); }
+
+ std::string text();
+ void text( const std::string& newtext );
+
+ long align();
+ void align( long );
+
+ long fontsize() { return -1; }
+ void fontsize( long );
+
+ std::string fontfamily() { return ""; }
+ void fontfamily( const std::string& );
+
+ Arts::TextBottom bottom();
+ void bottom( Arts::TextBottom );
+
+}; // class
+
+} // namespace
+
+class RotateLabel : public QFrame {
+ Q_OBJECT
+public:
+ RotateLabel( QWidget*, const char* =0 );
+ void paintEvent( QPaintEvent* );
+
+ void fontfamily( QString );
+ void fontsize( int );
+ void title( QString );
+ QString title() { return _title; }
+
+ long align() { return _align; }
+ void align( long );
+
+ Arts::TextBottom bottom() { return _bottom; }
+ void bottom( Arts::TextBottom );
+private:
+ long _align;
+ Arts::TextBottom _bottom;
+ QString _title;
+};
+
+#endif
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klayoutbox_impl.cpp b/arts/gui/kde/klayoutbox_impl.cpp
new file mode 100644
index 00000000..e83ea5c7
--- /dev/null
+++ b/arts/gui/kde/klayoutbox_impl.cpp
@@ -0,0 +1,122 @@
+/*
+ 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, 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 "klayoutbox_impl.h"
+
+#include <qframe.h>
+#include <qlayout.h>
+#include <kdebug.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qpen.h>
+#include "kwidgetrepo.h"
+
+using namespace Arts;
+using namespace std;
+
+KLayoutBox_impl::KLayoutBox_impl( QFrame *widget ) : KFrame_impl( widget ? widget :new QFrame( 0 ) )
+{
+ _qframe = static_cast<QFrame*>( _qwidget );
+ _layout = new QBoxLayout( _qframe, QBoxLayout::LeftToRight );
+}
+KLayoutBox_impl::~KLayoutBox_impl() {
+}
+
+void KLayoutBox_impl::addWidget( Arts::Widget widget, long stretch, long align ) {
+ widget.parent( self() );
+ this->_addChild( widget, "layoutbox_item" );
+ QWidget * tmp = KWidgetRepo::the()->lookupQWidget( widget.widgetID() );
+ _layout->addWidget( tmp, stretch, align );
+}
+
+void KLayoutBox_impl::insertWidget( long index, Arts::Widget widget, long stretch, long align ) {
+ widget.parent( self() );
+ this->_addChild( widget, "layoutbox_item" );
+ QWidget * tmp = KWidgetRepo::the()->lookupQWidget( widget.widgetID() );
+ _layout->insertWidget( index, tmp, stretch, align );
+}
+
+void KLayoutBox_impl::addStretch( long n ) { _layout->addStretch( n ); }
+void KLayoutBox_impl::addSpace( long n ) { _layout->addSpacing( n ); }
+void KLayoutBox_impl::addStrut( long n ) { _layout->addStrut( n ); }
+void KLayoutBox_impl::addSeparator( long stretch, long align ) {
+ _layout->addWidget( new KLayoutBox_Separator( _qframe ), stretch, align );
+}
+void KLayoutBox_impl::addLine( long width, long space, long stretch, long align ) {
+ _layout->addWidget( new KLayoutBox_Line( width, space, _qframe ), stretch, align );
+}
+
+long KLayoutBox_impl::spacing() { return _layout->spacing(); }
+void KLayoutBox_impl::spacing( long n ) { _layout->setSpacing( n ); }
+
+long KLayoutBox_impl::layoutmargin() { return _layout->margin(); }
+void KLayoutBox_impl::layoutmargin( long n ) { _layout->setMargin( n ); this->margin( n ); }
+
+Direction KLayoutBox_impl::direction() { return Arts::Direction( _layout->direction() ); }
+void KLayoutBox_impl::direction( Direction d ) { _layout->setDirection( QBoxLayout::Direction( d ) ); }
+
+REGISTER_IMPLEMENTATION( KLayoutBox_impl );
+
+KLayoutBox_Separator::KLayoutBox_Separator( QWidget* p, const char* n ) : QWidget( p,n ) {
+//kdDebug() << k_funcinfo << endl;
+}
+
+void KLayoutBox_Separator::resizeEvent( QResizeEvent* ) { kdDebug() << k_funcinfo << size() << endl; }
+
+void KLayoutBox_Separator::paintEvent( QPaintEvent* ) {
+//kdDebug() << k_funcinfo << size() << endl;
+ QPainter p( this );
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if ( width() < height() ) flags |= QStyle::Style_Horizontal;
+ style().drawPrimitive( QStyle::PE_Splitter, &p, rect(), colorGroup(), flags );
+}
+
+QSize KLayoutBox_Separator::minimumSizeHint() const {
+ int wh = style().pixelMetric( QStyle::PM_SplitterWidth, this );
+ return QSize( wh, wh );
+}
+
+KLayoutBox_Line::KLayoutBox_Line( int width, int space, QWidget* p, const char* n )
+ : QWidget( p,n )
+ , _width( width )
+ , _space( space )
+{
+//kdDebug() << k_funcinfo << size() << endl;
+}
+
+
+void KLayoutBox_Line::paintEvent( QPaintEvent* ) {
+//kdDebug() << k_funcinfo << size() << endl;
+ QPainter p( this );
+ p.setPen( QPen( colorGroup().foreground(), _width ) );
+ if ( width() > height() ) p.drawLine( 0, height()/2, width(), height()/2 );
+ else p.drawLine( width()/2, 0, width()/2, height() );
+}
+
+QSize KLayoutBox_Line::minimumSizeHint() const {
+//kdDebug() << k_funcinfo << size() << endl;
+ int wh = _width + 2* _space;
+ return QSize( wh, wh );
+}
+
+#include <klayoutbox_impl.moc>
+
+// vim: sw=4 ts=4
+
diff --git a/arts/gui/kde/klayoutbox_impl.h b/arts/gui/kde/klayoutbox_impl.h
new file mode 100644
index 00000000..fbb88630
--- /dev/null
+++ b/arts/gui/kde/klayoutbox_impl.h
@@ -0,0 +1,103 @@
+ /*
+
+ 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, 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.
+
+ */
+
+#ifndef ARTS_KLAYOUTBOX_IMPL_H
+#define ARTS_KLAYOUTBOX_IMPL_H
+
+#include "kframe_impl.h"
+
+#include <artsgui.h>
+#include <kdelibs_export.h>
+
+class KArtsWidget;
+class QBoxLayout;
+
+namespace Arts {
+
+class KDE_EXPORT KLayoutBox_impl : virtual public Arts::LayoutBox_skel,
+ public Arts::KFrame_impl
+{
+protected:
+ QFrame* _qframe;
+ QBoxLayout* _layout;
+
+ LayoutBox self() { return LayoutBox::_from_base( _copy() ); }
+public:
+ KLayoutBox_impl( QFrame* w=0 );
+ ~KLayoutBox_impl();
+
+ Direction direction();
+ void direction( Direction );
+
+ void addWidget( Arts::Widget, long, long );
+ void addWidget( Arts::Widget w, long n ) { addWidget( w,n,0 ); }
+ void addWidget( Arts::Widget w ) { addWidget( w,0,0 ); }
+
+ void insertWidget( long, Arts::Widget, long, long );
+ void insertWidget( long i, Arts::Widget w, long n ) { insertWidget( i,w,n,0 ); }
+ void insertWidget( long i, Arts::Widget w ) {insertWidget( i,w,0,0 ); }
+
+ void addStretch( long );
+ void addStretch() { addStretch( 0 ); }
+
+ void addSpace( long );
+ void addStrut( long );
+
+ void addSeparator( long, long );
+ void addSeparator( long ) { addSeparator( 0, 0 ); }
+ void addSeparator() { addSeparator( 0, 0 ); }
+
+ void addLine( long, long, long, long );
+ void addLine( long width, long space, long stretch ) { addLine( width, space, stretch, 0 ); }
+ void addLine( long width, long space ) { addLine( width, space, 0, 0 ); }
+
+ long spacing();
+ void spacing( long );
+
+ long layoutmargin();
+ void layoutmargin( long );
+}; // class
+
+} // namespace
+
+class KDE_EXPORT KLayoutBox_Separator : public QWidget {
+ Q_OBJECT
+public:
+ KLayoutBox_Separator( QWidget*, const char* =0 );
+ void resizeEvent( QResizeEvent* );
+ void paintEvent( QPaintEvent* );
+ QSize minimumSizeHint() const;
+};
+
+class KLayoutBox_Line : public QWidget {
+ Q_OBJECT
+private:
+ int _width, _space;
+public:
+ KLayoutBox_Line( int, int, QWidget*, const char* =0 );
+ void paintEvent( QPaintEvent* );
+ QSize minimumSizeHint() const;
+};
+
+#endif
+
+// vim: sw=4 ts=4
+
diff --git a/arts/gui/kde/klevelmeter_firebars.cpp b/arts/gui/kde/klevelmeter_firebars.cpp
new file mode 100644
index 00000000..916c6b53
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_firebars.cpp
@@ -0,0 +1,125 @@
+/*
+ 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 "klevelmeter_firebars.h"
+
+#include <kdebug.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+KLevelMeter_FireBars_private::KLevelMeter_FireBars_private( KLevelMeter_FireBars* p, const char* n ) : QWidget( p,n ) {
+ _parent = p;
+ _pixmap = new QPixmap( 0,0 );
+// setPaletteBackgroundColor( QColor( 0,0,255 ) );
+}
+void KLevelMeter_FireBars_private::paintEvent( QPaintEvent* ) {
+ QPainter p;
+ if ( _pixmap->size() != this->size() ) {
+ _pixmap->resize( this->size() );
+ p.begin( _pixmap );
+ _pixmap->fill( paletteBackgroundColor() );
+ if ( dir==Arts::BottomToTop || dir==Arts::TopToBottom ) {
+kdDebug() << k_funcinfo << dir << endl;
+ //if ( dir==Arts::BottomToTop ) p.translate( 0, rect().bottom() );
+ for ( int i=this->height(); i>0; i-- ) {
+ p.setPen( _parent->color( 1-float( i )/this->height() ) );
+ //if ( dir==Arts::BottomToTop ) i *= -1;
+ p.drawLine( 0, i, this->width(), i );
+ }
+ } else {
+ if ( dir==Arts::RightToLeft ) p.translate( 0, rect().right() );
+ for ( int i=this->width(); i>0; i-- ) {
+ p.setPen( _parent->color( float( i )/this->width() ) );
+ if ( dir==Arts::RightToLeft ) i *= -1;
+ p.drawLine( i, 0, i, this->height() );
+ }
+ }
+ p.end();
+ }
+ p.begin( this );
+ p.translate( 0,0 );
+ p.drawPixmap( QPoint( 0,0 ), *_pixmap );
+ p.end();
+}
+
+KLevelMeter_FireBars::KLevelMeter_FireBars( Arts::KLevelMeter_impl* impl, QWidget* parent, long substyle, long count, Arts::Direction dir, float _dbmin, float _dbmax ) : KLevelMeter_Template( impl, parent, substyle, count, dir, _dbmin, _dbmax ) {
+//kdDebug()<<"KLevelMeter_FireBars::KLevelMeter_FireBars( Arts::KLevelMeter_impl* "<<impl<<", QWidget* "<<parent<<", long "<<substyle<<", long "<<count<<", float "<<_dbmin<<", float "<<_dbmax<<" )"<<endl;
+ this->setMinimumSize( 5, 5 );
+ _bar = new KLevelMeter_FireBars_private( this, 0 );
+ _peakwidget = new QWidget( this );
+ _peakwidget->resize( size() );
+ _peakwidget->setPaletteBackgroundColor( color( 1 ) );
+ _peakwidget->hide();
+}
+
+void KLevelMeter_FireBars::invalue( float n, float p ) {
+//kdDebug()<<"KLevelMeter_FireBars::invalue( float n )"<<endl;
+ if ( _peakwidget->size() != this->size() ) _peakwidget->setGeometry( 0,0, size().width(), size().height() );
+ _value = amptondb( n );
+ _peak = amptondb( p );
+ if ( _peak > 1 )_peakwidget->show(); else _peakwidget->hide();
+ _bar->dir = _dir;
+ switch ( _dir ) {
+ default:
+ case Arts::BottomToTop:
+ _bar->setGeometry( 0, int( this->height()-_value*this->height() ), this->width(), this->height() );
+ break;
+ case Arts::TopToBottom:
+ _bar->setGeometry( 0, -int( this->height()-_value*this->height() ), this->width(), this->height() );
+ break;
+ case Arts::LeftToRight:
+ _bar->setGeometry( -int( this->width()-_value*this->width() ), 0, this->width(), this->height() );
+ break;
+ case Arts::RightToLeft:
+ _bar->setGeometry( int( this->width()-_value*this->width() ), 0, this->width(), this->height() );
+ break;
+ }
+ repaint();
+}
+
+void KLevelMeter_FireBars::paintEvent( QPaintEvent* ) {
+ QPainter p( this );
+ //p.setPen( NoPen );
+ p.setPen( QColor( 0,0,255 ) );
+ // PeakBar
+ if ( _peak > 1.0/1000 ) {
+ if ( _dir == Arts::BottomToTop || _dir == Arts::TopToBottom ) {
+ if ( _dir == Arts::BottomToTop ) p.translate( 0, rect().bottom() );
+ int h = int( this->height()*_peak );
+ if ( _dir==Arts::BottomToTop ) h *= -1;
+ p.drawLine( 0, h, this->width(), h );
+ } else {
+ if ( _dir==Arts::RightToLeft ) p.translate( 0, rect().right() );
+ int w = int( this->width()* _peak );
+ if ( _dir==Arts::RightToLeft ) w *= -1;
+ p.drawLine( w, 0, w, this->height() );
+ }
+ }
+}
+
+/**
+ Planned feature: a little Tooltip showing the actual value of the volume in deziBel and perhaps as linear scaleFactor
+*/
+void KLevelMeter_FireBars::mouseMoveEvent( QMouseEvent* /*qme*/ ) {
+//kdDebug()<<"KLevelMeter_FireBars::mouseMoveEvent(QMouseEvent* "<<qme<<" )"<<endl;
+}
+
+#include <klevelmeter_firebars.moc>
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_firebars.h b/arts/gui/kde/klevelmeter_firebars.h
new file mode 100644
index 00000000..49ffa75a
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_firebars.h
@@ -0,0 +1,58 @@
+/*
+ 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_KLEVELMETER_FIREBARS_H
+#define ARTS_KLEVELMETER_FIREBARS_H
+
+#include "klevelmeter_template.h"
+
+class QPixmap;
+class KLevelMeter_FireBars;
+
+class KLevelMeter_FireBars_private : public QWidget {
+ Q_OBJECT
+public:
+ KLevelMeter_FireBars_private( KLevelMeter_FireBars*, const char* );
+ void paintEvent( QPaintEvent* );
+
+ Arts::Direction dir;
+private:
+ KLevelMeter_FireBars* _parent;
+ QPixmap *_pixmap;
+};
+
+class KLevelMeter_FireBars : public KLevelMeter_Template {
+ Q_OBJECT
+public:
+ KLevelMeter_FireBars( Arts::KLevelMeter_impl*, QWidget* =0, long substyle=0, long count=0, Arts::Direction =Arts::BottomToTop, float _dbmin=-24, float _dbmax=6 );
+
+ void invalue( float, float =0 );
+
+ void paintEvent( QPaintEvent* );
+
+ void mouseMoveEvent( QMouseEvent* );
+private:
+ float _value, _peak;
+ KLevelMeter_FireBars_private *_bar;
+ QWidget* _peakwidget;
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_impl.cpp b/arts/gui/kde/klevelmeter_impl.cpp
new file mode 100644
index 00000000..ff04edde
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_impl.cpp
@@ -0,0 +1,131 @@
+/*
+ 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 "klevelmeter_impl.h"
+
+#include <math.h>
+
+#include <qframe.h>
+#include <kdebug.h>
+#include <qlayout.h>
+#include <kartswidget.h>
+
+#include "klevelmeter_private.h"
+#include "klevelmeter_private.moc"
+#include "klevelmeter_template.h"
+#include "klevelmeter_template.moc"
+
+#include "klevelmeter_small.h"
+#include "klevelmeter_linebars.h"
+#include "klevelmeter_firebars.h"
+#include "klevelmeter_normalbars.h"
+
+using namespace Arts;
+using namespace std;
+
+KLevelMeter_Private::KLevelMeter_Private( KLevelMeter_impl* impl, QFrame* frame, LevelMeterStyle defstyle, QObject* parent, const char* name )
+ : QObject( parent, name )
+ , _impl( impl )
+ , _frame( frame )
+ , _levelmeter( 0 )
+ , _style( defstyle )
+ , _substyle( 0 )
+ , _count( 20 )
+ , _direction( Arts::BottomToTop )
+ , _peak( 20 ), _peakvalue( 0.0 )
+ , _dbmin( -36 ), _dbmax( 0 )
+{
+ _layout = new QBoxLayout( _frame, QBoxLayout::LeftToRight );
+}
+
+void KLevelMeter_Private::createWidget() {
+ if ( _levelmeter != 0 ) { _levelmeter->hide(); delete _levelmeter; _levelmeter=0; }
+ switch ( _style ) {
+ case lmNormalBars:
+ _levelmeter = new KLevelMeter_NormalBars( _impl, _frame, _substyle, _count, _direction, _dbmin, _dbmax );
+ break;
+ case lmFireBars:
+ _levelmeter = new KLevelMeter_FireBars( _impl, _frame, _substyle, _count, _direction, _dbmin, _dbmax );
+ break;
+ default:
+ case lmLineBars:
+ _levelmeter = new KLevelMeter_LineBars( _impl, _frame, _substyle, _count, _direction, _dbmin, _dbmax );
+ break;
+ case lmSmall:
+ _levelmeter = new KLevelMeter_Small( _impl, _frame, _substyle, _count, _direction, _dbmin, _dbmax );
+ break;
+ }
+ _layout->addWidget( _levelmeter );
+ _levelmeter->show();
+ _levelmeter->setMinimumSize( 10,10 );
+}
+
+KLevelMeter_impl::KLevelMeter_impl( QFrame* w ) : Arts::KFrame_impl( w ? w : new QFrame( 0 ) ) {
+//kdDebug()<<"KLevelMeter_impl::KLevelMeter_impl( QFrame* "<<w<<" )"<<endl;
+ p = new KLevelMeter_Private( this, _qframe, lmLineBars );
+ p->createWidget();
+}
+
+LevelMeterStyle KLevelMeter_impl::style() { return p->_style; }
+
+void KLevelMeter_impl::style( LevelMeterStyle style ) {
+ if ( p->_style!=style )
+ {
+ p->_style = style;
+ p->createWidget();
+ }
+}
+
+long KLevelMeter_impl::substyle() { return p->_substyle; }
+void KLevelMeter_impl::substyle( long n ) { p->_substyle = n; p->_levelmeter->substyle( n ); }
+
+long KLevelMeter_impl::count() { return p->_levelmeter->count(); }
+void KLevelMeter_impl::count( long n ) { p->_levelmeter->count( n ); p->_count = n; }
+
+long KLevelMeter_impl::peakfalloff() { return p->_peak; }
+void KLevelMeter_impl::peakfalloff( long n ) { p->_peak = n; }
+
+float KLevelMeter_impl::mindB() { return p->_levelmeter->dbmin; }
+void KLevelMeter_impl::mindB( float n ) { p->_levelmeter->dbmin = n; p->_dbmin = n; }
+float KLevelMeter_impl::maxdB() { return p->_levelmeter->dbmax; }
+void KLevelMeter_impl::maxdB( float n ) { p->_levelmeter->dbmax = n; p->_dbmax = n; }
+
+float KLevelMeter_impl::invalue() { return 0.0; }
+void KLevelMeter_impl::invalue( float n ) {
+//kdDebug()<<"KLevelMeter_impl::invalue( float n="<<n<<" )"<<endl;
+ if ( p->_peak ) {
+ p->_peakvalue = ( p->_peak*p->_peakvalue + n ) / ( p->_peak + 1 );
+ if ( p->_peakvalue < n ) p->_peakvalue = n;
+ }
+ else p->_peakvalue = 0.0;
+ p->_levelmeter->invalue( n, p->_peakvalue );
+}
+
+Arts::Direction KLevelMeter_impl::direction() { return p->_direction; }
+void KLevelMeter_impl::direction( Arts::Direction n ) {
+ p->_direction = n;
+ p->_levelmeter->direction( n );
+}
+
+REGISTER_IMPLEMENTATION( KLevelMeter_impl );
+
+// vim: sw=4 ts=4
+
diff --git a/arts/gui/kde/klevelmeter_impl.h b/arts/gui/kde/klevelmeter_impl.h
new file mode 100644
index 00000000..53dc5fe2
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_impl.h
@@ -0,0 +1,70 @@
+/*
+ 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_KLEVELMETER_IMPL_H
+#define ARTS_KLEVELMETER_IMPL_H
+
+#include "artsgui.h"
+
+#include "kframe_impl.h"
+
+class QFrame;
+
+class KLevelMeter_Private;
+
+namespace Arts { // namespace Arts
+
+class KLevelMeter_impl : virtual public Arts::LevelMeter_skel,
+ virtual public Arts::KFrame_impl
+{
+private:
+ KLevelMeter_Private *p;
+public:
+ KLevelMeter_impl( QFrame* =0 );
+
+ LevelMeterStyle style();
+ void style( LevelMeterStyle );
+
+ long substyle();
+ void substyle( long );
+
+ long count();
+ void count( long );
+
+ long peakfalloff();
+ void peakfalloff( long );
+
+ float mindB();
+ void mindB( float );
+ float maxdB();
+ void maxdB( float );
+
+ float invalue();
+ void invalue( float );
+
+ Arts::Direction direction();
+ void direction( Arts::Direction );
+}; //class KLevelMeter_impl
+
+} // namespace Arts
+
+#endif
+// vim: sw=4 ts=4
+
diff --git a/arts/gui/kde/klevelmeter_linebars.cpp b/arts/gui/kde/klevelmeter_linebars.cpp
new file mode 100644
index 00000000..108c5a94
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_linebars.cpp
@@ -0,0 +1,109 @@
+/*
+ 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 "klevelmeter_linebars.h"
+
+#include <kdebug.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+KLevelMeter_LineBars::KLevelMeter_LineBars( Arts::KLevelMeter_impl* impl, QWidget* parent, long substyle, long count, Arts::Direction dir, float _dbmin, float _dbmax ) : KLevelMeter_Template( impl, parent, substyle, count, dir, _dbmin, _dbmax )
+ , _value( 0.0 )
+ , _peak( 0.0 )
+{
+//kdDebug()<<"KLevelMeter_LineBars::KLevelMeter_LineBars( Arts::KLevelMeter_impl* "<<impl<<", QWidget* "<<parent<<", long "<<substyle<<", long "<<count<<", Arts::Direction "<<dir<<", float "<<_dbmin<<", float "<<_dbmax<<" )"<<endl;
+ this->setMinimumSize( 5, 5 );
+ this->substyle( substyle );
+ _stdcolors = colorGroup();
+ setBackgroundMode( Qt::NoBackground );
+}
+
+void KLevelMeter_LineBars::invalue( float n, float p ) {
+ _value = amptondb( n );
+ _peak = amptondb( p );
+ repaint();
+}
+
+void KLevelMeter_LineBars::substyle( long n ) {
+ //kdDebug() << k_funcinfo << n << endl;
+ _substyle = n;
+}
+long KLevelMeter_LineBars::substyle() { return _substyle; }
+
+void KLevelMeter_LineBars::paintEvent( QPaintEvent* ) {
+ QPixmap pm( size() );
+ QPainter p( &pm );
+
+ switch ( _dir ) {
+ case Arts::BottomToTop:
+ break;
+ case Arts::TopToBottom:
+ p.rotate( 180.0 );
+ p.translate( -width() + 1, -height() + 1 );
+ break;
+ case Arts::LeftToRight:
+ p.rotate( 90.0 );
+ p.translate( 0, -width() + 1 );
+ break;
+ case Arts::RightToLeft:
+ p.rotate( 270.0 );
+ p.translate( -height() + 1, 0 );
+ break;
+ }
+
+ if ( _substyle & 1 )
+ p.setBrush( ( _peak<1 )?QColor( 0,0,255 ):QColor( 255,0,0 ) );
+ else
+ p.setBrush( ( _peak<1 )?color( _value ):QColor( 255,0,0 ) );
+
+ QColor bgcolor = ( _substyle & 2 ) ? p.brush().color().dark() : _stdcolors.background();
+ pm.fill( bgcolor );
+
+ p.setPen( NoPen );
+
+ QSize s = size();
+ if ( Arts::LeftToRight == _dir || Arts::RightToLeft == _dir )
+ s.transpose();
+
+ // Value
+ int h = int( s.height() * _value );
+ int top = s.height() - h;
+ int w = s.width();
+ p.drawRect( 0, top, w, h );
+ // PeakBar
+ if ( _peak > 1.0/1000 && _peak <= 1.0 ) {
+ p.setPen( QColor( 255-bgcolor.red(), 255-bgcolor.green(), 255-bgcolor.blue() ) );
+ top = int( s.height() * ( 1 - _peak ) );
+ p.drawLine( 0, top, w, top );
+ }
+
+ bitBlt( this, 0, 0, &pm, 0, 0, pm.width(), pm.height(), CopyROP, true );
+}
+
+/**
+ Planned feature: a little Tooltip showing the actual value of the volume in deziBel and perhaps as linear scaleFactor
+*/
+void KLevelMeter_LineBars::mouseMoveEvent( QMouseEvent* /*qme*/ ) {
+//kdDebug()<<"KLevelMeter_LineBars::mouseMoveEvent(QMouseEvent* "<<qme<<" )"<<endl;
+//kdDebug()<<"qme.y()="<<this->height()-qme->y()<<" db="<<db<<" dbtoamp(db)="<<dbtoamp( db )<<endl;
+}
+
+#include <klevelmeter_linebars.moc>
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_linebars.h b/arts/gui/kde/klevelmeter_linebars.h
new file mode 100644
index 00000000..f512b6d1
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_linebars.h
@@ -0,0 +1,46 @@
+/*
+ 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_KLEVELMETER_LINEBARS_H
+#define ARTS_KLEVELMETER_LINEBARS_H
+
+#include "klevelmeter_template.h"
+
+class KLevelMeter_LineBars : public KLevelMeter_Template {
+ Q_OBJECT
+public:
+ KLevelMeter_LineBars( Arts::KLevelMeter_impl*, QWidget* =0, long substyle=0, long count=0, Arts::Direction =Arts::BottomToTop, float _dbmin=-24, float _dbmax=6 );
+
+ void invalue( float, float =0 );
+
+ void substyle( long );
+ long substyle();
+
+ void paintEvent( QPaintEvent* );
+
+ void mouseMoveEvent( QMouseEvent* );
+private:
+ float _value, _peak;
+ long _substyle;
+ QColorGroup _stdcolors;
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_normalbars.cpp b/arts/gui/kde/klevelmeter_normalbars.cpp
new file mode 100644
index 00000000..a078eccf
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_normalbars.cpp
@@ -0,0 +1,81 @@
+/*
+ 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 "klevelmeter_normalbars.h"
+
+#include <kdebug.h>
+#include <qpainter.h>
+#include <qlayout.h>
+
+KLevelMeter_NormalBars::KLevelMeter_NormalBars( Arts::KLevelMeter_impl* impl, QWidget* parent, long substyle, long count, Arts::Direction dir, float _dbmin, float _dbmax ) : KLevelMeter_Template( impl, parent, substyle, count, dir, _dbmin, _dbmax ) {
+//kdDebug()<<"KLevelMeter_NormalBars::KLevelMeter_NormalBars( Arts::KLevelMeter_impl* "<<impl<<", QWidget* "<<parent<<", long "<<substyle<<", long "<<count<<", float "<<_dbmin<<", float "<<_dbmax<<" )"<<endl;
+ _layout = new QBoxLayout( this, QBoxLayout::BottomToTop );
+}
+
+void KLevelMeter_NormalBars::invalue( float n, float p ) {
+ //kdDebug()<<"KLevelMeter_NormalBars::invalue( float "<<n<<", float "<<p<<" )"<<endl;
+ _peak = amptondb( p );
+ _value = amptondb( n );
+ if ( _dir != Arts::Direction( _layout->direction() ) ) _layout->setDirection( QBoxLayout::Direction( _dir ) );
+ for ( uint i=0; i<bars.count(); i++ ) bars.at( i )->setValue( _value );
+}
+
+long KLevelMeter_NormalBars::count() { return _count; }
+void KLevelMeter_NormalBars::count( long n ) {
+//kdDebug()<<"KLevelMeter_NormalBars::count( long "<<n<<" )"<<endl;
+ if ( n != _count && n>0 ) {
+ _count = n;
+ resizeEvent();
+ }
+}
+
+void KLevelMeter_NormalBars::resizeEvent( QResizeEvent* ) {
+ //kdDebug()<<"KLevelMeter_NormalBars::resizeEvent( QResizeEvent* )"<<endl;
+uint barscount = _count;
+ //kdDebug()<<"[1] barscount="<<barscount<<" bars.count()="<<bars.count()<<endl;
+ if ( _dir==Arts::BottomToTop || _dir==Arts::TopToBottom ) {
+ if ( unsigned( this->height() ) < barscount ) barscount = this->height();
+ } else {
+ if ( unsigned( this->width() ) < barscount ) barscount = this->width();
+ }
+ if ( barscount != bars.count() ) {
+ //kdDebug()<<"[2] barscount="<<barscount<<" bars.count()="<<bars.count()<<endl;
+ while ( bars.count() > 0 ) {
+ bars.last()->hide();
+ delete bars.last();
+ bars.removeLast();
+ //kdDebug()<<"[2.5] barscount="<<barscount<<" bars.count()="<<bars.count()<<endl;
+ }
+ //kdDebug()<<"[3] barscount="<<barscount<<" bars.count()="<<bars.count()<<endl;
+ uint i=0;
+ while ( bars.count()<barscount ) {
+ Bar* tmp = new Bar( i*1.0/barscount, ( i+1 )*1.0/barscount, color( i*1.0/barscount ), this );
+ tmp->show();
+ _layout->addWidget( tmp );
+ bars.append( tmp );
+ i++;
+ //kdDebug()<<"[3."<<i<<"] barscount="<<barscount<<" bars.count()="<<bars.count()<<endl;
+ }
+ //kdDebug()<<"[4] barscount="<<barscount<<" bars.count()="<<bars.count()<<endl;
+ }
+}
+
+#include <klevelmeter_normalbars.moc>
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_normalbars.h b/arts/gui/kde/klevelmeter_normalbars.h
new file mode 100644
index 00000000..6e319365
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_normalbars.h
@@ -0,0 +1,75 @@
+/*
+ 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_KLEVELMETER_NORMALBARS_H
+#define ARTS_KLEVELMETER_NORMALBARS_H
+
+#include "klevelmeter_template.h"
+
+#include <qptrlist.h>
+
+class Bar;
+class QBoxLayout;
+
+class KLevelMeter_NormalBars : public KLevelMeter_Template {
+ Q_OBJECT
+public:
+ KLevelMeter_NormalBars( Arts::KLevelMeter_impl*, QWidget* =0, long substyle=0, long count=25, Arts::Direction =Arts::BottomToTop, float _dbmin=-24, float _dbmax=6 );
+
+ void invalue( float, float =0 );
+
+ void count( long );
+ long count();
+
+ void resizeEvent( QResizeEvent* =0 );
+private:
+ float _value, _peak;
+ QPtrList <Bar> bars;
+// long _count;
+ QBoxLayout *_layout;
+};
+
+class Bar : public QWidget {
+ Q_OBJECT
+private:
+ float _min, _max;
+ QColor _color;
+ bool _on;
+public:
+ Bar( float min, float max, QColor color, QWidget* parent ) : QWidget( parent ), _min( min ), _max( max ), _color( color ), _on( false ) {
+ setBackgroundColor( _color.dark() );
+ }
+ void setValue( float n ) {
+ if ( n>_min /*&& n<_max*/ ) on( true );
+ else on( false );
+ }
+ void on( bool n ) {
+ if ( _on != n )
+ {
+ _on = n;
+ if ( _on ) setBackgroundColor( _color );
+ else setBackgroundColor( _color.dark() );
+ }
+ }
+ void setValues( float min, float max, QColor color ) { _min = min; _max = max; _color = color; on( _on ); }
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_private.h b/arts/gui/kde/klevelmeter_private.h
new file mode 100644
index 00000000..c1826c63
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_private.h
@@ -0,0 +1,55 @@
+/*
+ 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_KLEVELMETER_PRIVATE_H
+#define ARTS_KLEVELMETER_PRIVATE_H
+
+#include <qwidget.h>
+
+#include "klevelmeter_impl.h"
+
+class KLevelMeter_Template;
+class QBoxLayout;
+class KArtsWidget;
+
+class KLevelMeter_Private : public QObject {
+ Q_OBJECT
+public:
+ Arts::KLevelMeter_impl* _impl;
+ QFrame* _frame;
+ QBoxLayout *_layout;
+
+ KLevelMeter_Template *_levelmeter;
+
+ Arts::LevelMeterStyle _style;
+ long _substyle;
+ long _count;
+ Arts::Direction _direction;
+ long _peak;
+ float _peakvalue;
+ float _dbmin, _dbmax;
+
+ KLevelMeter_Private( Arts::KLevelMeter_impl* impl, QFrame* frame, Arts::LevelMeterStyle defstyle, QObject* =0, const char* =0 );
+
+ void createWidget();
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_small.cpp b/arts/gui/kde/klevelmeter_small.cpp
new file mode 100644
index 00000000..94ba0df0
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_small.cpp
@@ -0,0 +1,59 @@
+/*
+ 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 "klevelmeter_small.h"
+
+#include <kdebug.h>
+#include <qpainter.h>
+
+KLevelMeter_Small::KLevelMeter_Small( Arts::KLevelMeter_impl* impl, QWidget* parent, long substyle, long count, Arts::Direction dir, float _dbmin, float _dbmax ) : KLevelMeter_Template( impl, parent, substyle, count, dir, _dbmin, _dbmax ) {
+//kdDebug()<<"KLevelMeter_Small::KLevelMeter_Small( Arts::KLevelMeter_impl* "<<impl<<", QWidget* "<<parent<<", long "<<substyle<<", long "<<count<<", float "<<_dbmin<<", float "<<_dbmax<<" )"<<endl;
+}
+
+void KLevelMeter_Small::invalue( float n, float p ) {
+//kdDebug()<<"KLevelMeter_Small::invalue( float "<<n<<", float "<<p<<" )"<<endl;
+ _peak = amptondb( p );
+ if ( n ) this->setBackgroundColor( color( amptondb( n ) ) );
+ else this->setBackgroundColor( QColor( 0,255,0 ).dark() );
+}
+
+void KLevelMeter_Small::paintEvent( QPaintEvent* /*qpe*/ ) {
+//kdDebug()<<"KLevelMeter_Small::paintEvent( QPaintEvent* "<<qpe<<" )"<<endl;
+ if ( _peak && _peak <= 1.0 ) {
+ QPainter p( this );
+ //p.setPen( QColor( 0,0,0 ) );
+ QColor bgcolor = this->paletteBackgroundColor();
+ p.setPen( QColor( 255-bgcolor.red(), 255-bgcolor.green(), 255-bgcolor.blue() ) );
+ if ( _dir==Arts::BottomToTop || _dir==Arts::TopToBottom ) {
+ if ( _dir==Arts::BottomToTop ) p.translate( 0, rect().bottom() );
+ int h = int( this->height() * _peak );
+ if ( _dir==Arts::BottomToTop ) h *= -1;
+ p.drawLine( 0, h, this->width(), h );
+ } else {
+ if ( _dir==Arts::RightToLeft ) p.translate( 0, rect().right() );
+ int w = int( this->width() * _peak );
+ if ( _dir==Arts::RightToLeft ) w *= -1;
+ p.drawLine( w, 0, w, this->height() );
+ }
+ }
+}
+
+#include <klevelmeter_small.moc>
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_small.h b/arts/gui/kde/klevelmeter_small.h
new file mode 100644
index 00000000..837c2bf6
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_small.h
@@ -0,0 +1,39 @@
+/*
+ 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_KLEVELMETER_SMALL_H
+#define ARTS_KLEVELMETER_SMALL_H
+
+#include "klevelmeter_template.h"
+
+class KLevelMeter_Small : public KLevelMeter_Template {
+ Q_OBJECT
+public:
+ KLevelMeter_Small( Arts::KLevelMeter_impl*, QWidget* =0, long substyle=0, long count=0, Arts::Direction =Arts::BottomToTop, float _dbmin=-24, float _dbmax=6 );
+
+ void invalue( float, float =0 );
+
+ void paintEvent( QPaintEvent* );
+private:
+ float _peak;
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klevelmeter_template.h b/arts/gui/kde/klevelmeter_template.h
new file mode 100644
index 00000000..f1557d28
--- /dev/null
+++ b/arts/gui/kde/klevelmeter_template.h
@@ -0,0 +1,70 @@
+/*
+ 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_KLEVELMETER_TEMPLATE_H
+#define ARTS_KLEVELMETER_TEMPLATE_H
+
+#include <qwidget.h>
+
+#include <math.h>
+
+#include "dbvolcalc.h"
+
+#include "klevelmeter_impl.h"
+
+class KLevelMeter_Template : public QWidget, public dB2VolCalc {
+ Q_OBJECT
+public:
+ Arts::KLevelMeter_impl* _impl;
+
+ KLevelMeter_Template( Arts::KLevelMeter_impl* impl, QWidget* p, long /*substyle*/, long count, Arts::Direction dir, float _dbmin, float _dbmax )
+ : QWidget( p )
+ , dB2VolCalc( _dbmin, _dbmax )
+ , _impl( impl )
+ , _count( count )
+ , nilline( 3/4.0 )
+ , _dir( dir )
+ {}
+
+ virtual void invalue( float, float =0 ) =0;
+
+ virtual void substyle( long ) {}
+ virtual long substyle() { return 0; }
+
+ virtual void count( long ) {}
+ virtual long count() { return 0; }
+ long _count;
+
+ void direction( Arts::Direction dir ) { _dir = dir; }
+ Arts::Direction direction() { return _dir; }
+
+ float nilline;
+ /// Gives the colors between green and red
+ QColor color( float n ) {
+ return QColor( int( ( n<=nilline )?255*( 1/nilline )*n:255 ),
+ int( ( n<=1 && n>nilline )?255-255*( 1/nilline )*( n-nilline ):( ( n>1 )?0:255 ) ),
+ 0 );
+ }
+protected:
+ Arts::Direction _dir;
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klineedit_impl.cpp b/arts/gui/kde/klineedit_impl.cpp
new file mode 100644
index 00000000..473ace81
--- /dev/null
+++ b/arts/gui/kde/klineedit_impl.cpp
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2000 Stefan Westerfeld <stefan@space.twc.de>
+ 2001 Charles Samuels <charles@kde.org>
+ 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 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 "klineedit_impl.h"
+#include "klineedit_impl.moc"
+
+using namespace Arts;
+using namespace std;
+
+KLineEditStringMapper::KLineEditStringMapper(KLineEdit_impl *impl, KLineEdit *ke)
+ :impl(impl)
+{
+ connect(ke, SIGNAL(textChanged(const QString&)),
+ this, SLOT(textChanged(const QString&)));
+}
+
+void KLineEditStringMapper::textChanged(const QString& newText)
+{
+ impl->textChanged(newText.utf8().data());
+}
+
+KLineEdit_impl::KLineEdit_impl( KLineEdit * widget )
+ : KWidget_impl( widget ? widget : new KLineEdit )
+{
+ _klineedit = static_cast<KLineEdit*>( _qwidget );
+ ( void )new KLineEditStringMapper( this, _klineedit );
+}
+
+string KLineEdit_impl::text()
+{
+ return _klineedit->text().utf8().data();
+}
+
+void KLineEdit_impl::text(const string& newText)
+{
+ _klineedit->setText(QString::fromUtf8(newText.c_str()));
+}
+
+void KLineEdit_impl::textChanged(const string& newText)
+{
+ text_changed(newText);
+}
+
+string KLineEdit_impl::caption()
+{
+ return ""; // FIXME
+}
+
+void KLineEdit_impl::caption(const string& /*newCaption*/)
+{
+ // FIXME
+}
+
+REGISTER_IMPLEMENTATION(KLineEdit_impl);
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/klineedit_impl.h b/arts/gui/kde/klineedit_impl.h
new file mode 100644
index 00000000..a079a2dc
--- /dev/null
+++ b/arts/gui/kde/klineedit_impl.h
@@ -0,0 +1,63 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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.
+
+ */
+
+#ifndef klineedit_impl_h
+#define klineedit_impl_h
+
+#include "kwidget_impl.h"
+#include <klineedit.h>
+
+
+namespace Arts {
+
+class KLineEdit_impl : virtual public Arts::LineEdit_skel,
+ public Arts::KWidget_impl
+{
+protected:
+ KLineEdit * _klineedit;
+
+public:
+ KLineEdit_impl( KLineEdit * w = 0 );
+ void constructor( Widget p ) { parent( p ); }
+
+ std::string caption();
+ void caption(const std::string& newCaption);
+ std::string text();
+ void text(const std::string& newText);
+ void textChanged(const std::string& newText);
+};
+
+class KLineEditStringMapper :public QObject {
+ Q_OBJECT
+ KLineEdit_impl *impl;
+public:
+ KLineEditStringMapper(KLineEdit_impl *impl, KLineEdit *ed);
+public slots:
+ void textChanged(const QString& newText);
+};
+
+}
+
+#endif
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kpopupbox_impl.cpp b/arts/gui/kde/kpopupbox_impl.cpp
new file mode 100644
index 00000000..03651ea2
--- /dev/null
+++ b/arts/gui/kde/kpopupbox_impl.cpp
@@ -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, 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 "kpopupbox_impl.h"
+#include "kpopupbox_private.h"
+
+#include <qlayout.h>
+
+using namespace Arts;
+
+KPopupBox_impl::KPopupBox_impl( KPopupBox_widget *w ) : KFrame_impl( w ? w : new KPopupBox_widget )
+{
+ self().framestyle( Box ); self().margin( 1 ); self().linewidth( 1 );
+ self().vSizePolicy( spFixed ); self().hSizePolicy( spFixed );
+
+ if( !w ) w = static_cast<KPopupBox_widget *>( _qframe );
+
+ _widget = w;
+// _mapper = new KPopupBoxEventMapper( _widget, this );
+}
+KPopupBox_impl::~KPopupBox_impl() {
+}
+
+Direction KPopupBox_impl::direction() { return _widget->direction(); }
+void KPopupBox_impl::direction( Direction n ) { _widget->direction( n ); }
+
+void KPopupBox_impl::widget( Arts::Widget widget ) {
+ widget.parent( self() );
+ this->_addChild( widget, "PopupBox_child" );
+ _widget->setWidget( widget );
+}
+Arts::Widget KPopupBox_impl::widget() { return _widget->getWidget(); }
+
+std::string KPopupBox_impl::name() { return _name; }
+void KPopupBox_impl::name( const std::string& n ) { _name = ""; _name = n; _widget->name( n ); }
+
+// Following the private class:
+
+KPopupBox_widget::KPopupBox_widget( QWidget *parent, const char* name ) : QFrame( parent,name )
+{
+ this->setFrameShape( QFrame::Box );
+ this->setMargin( 1 ); this->setLineWidth( 1 );
+
+ _titlebar = new QFrame( this );
+ _titlebarlayout = new QBoxLayout( _titlebar, QBoxLayout::BottomToTop );
+ _titlebarlayout->setAutoAdd( true );
+
+ _showbutton = new ShowButton( _titlebar );
+ connect( _showbutton, SIGNAL( toggled( bool ) ), this, SLOT( hide( bool ) ) );
+ _drag = new HandleDrag( _titlebar );
+ connect( _drag, SIGNAL( clicked() ), _showbutton, SLOT( toggle() ) );
+ _ownbutton = new OwnButton( _titlebar );
+ connect( _ownbutton, SIGNAL( toggled( bool ) ), this, SLOT( own( bool ) ) );
+
+ _artswidget = new OwnWidget( _showbutton, this );
+
+ _layout = new QBoxLayout( this, QBoxLayout::LeftToRight );
+ _layout->addWidget( _titlebar , -1 );
+ _layout->addWidget( _artswidget, 20 );
+ _layout->addStretch( 0 );
+}
+KPopupBox_widget::~KPopupBox_widget() {
+}
+
+Arts::Direction KPopupBox_widget::direction() {
+ return Arts::Direction( _layout->direction() );
+}
+
+void KPopupBox_widget::direction( Arts::Direction n ) {
+ _layout->setDirection( QBoxLayout::Direction( n ) );
+ _showbutton->direction( QBoxLayout::Direction( n ) );
+ switch( n ) {
+ case LeftToRight:
+ case RightToLeft:
+ _titlebarlayout->setDirection( QBoxLayout::BottomToTop );
+ _drag->setMinimumHeight( 30 );
+ _drag->setMinimumWidth( 0 );
+ break;
+ case TopToBottom:
+ case BottomToTop:
+ _titlebarlayout->setDirection( QBoxLayout::RightToLeft );
+ _drag->setMinimumHeight( 0 );
+ _drag->setMinimumWidth( 30 );
+ }
+}
+
+void KPopupBox_widget::setWidget( Arts::Widget widget ) { _artswidget->setContent( widget ); }
+Arts::Widget KPopupBox_widget::getWidget() { return _artswidget->content(); }
+
+void KPopupBox_widget::hide( bool n ) {
+ if( n )
+ _artswidget->hide();
+ else
+ _artswidget->show();
+}
+
+void KPopupBox_widget::own( bool n ) {
+ if ( n )
+ _artswidget->reparent( 0, _artswidget->mapToGlobal( _artswidget->pos() ), !( _artswidget->isHidden() ) );
+ else
+ {
+ _artswidget->reparent( this, QPoint( 0,0 ), !( _artswidget->isHidden() ) );
+ _layout->insertWidget( 1, _artswidget, 20 );
+ }
+}
+
+void KPopupBox_widget::name( std::string n ) {
+ _artswidget->setCaption( n.c_str() );
+}
+
+REGISTER_IMPLEMENTATION( KPopupBox_impl );
+
+#include "kpopupbox_private.moc"
+
+// vim: sw=4 ts=4
+
diff --git a/arts/gui/kde/kpopupbox_impl.h b/arts/gui/kde/kpopupbox_impl.h
new file mode 100644
index 00000000..e3c8c250
--- /dev/null
+++ b/arts/gui/kde/kpopupbox_impl.h
@@ -0,0 +1,70 @@
+ /*
+
+ 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, 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.
+
+ */
+
+#ifndef KPOPUPBOX_IMPL_H
+#define KPOPUPBOX_IMPL_H
+
+#include <kframe_impl.h>
+#include <artsgui.h>
+
+class QBoxLayout;
+class KPopupBox_widget;
+//class KPopupBoxEventMapper; // The EventMapper isn't needed at present, but perhaps in the future...
+
+namespace Arts {
+
+/// The PopupBox
+
+class KPopupBox_impl : virtual public Arts::PopupBox_skel, public Arts::KFrame_impl
+{
+public:
+ /// selfreference like 'this'
+ PopupBox self() { return PopupBox::_from_base( _copy() ); }
+ /// Constructor
+ KPopupBox_impl( KPopupBox_widget *w=0 );
+ ~KPopupBox_impl();
+
+ /// The name of the widget
+ std::string name();
+ void name( const std::string & );
+
+ /// The direction. LeftToRight (true) or TopToBottom (false). May get other values in the future.
+ Direction direction();
+ void direction( Direction );
+
+ /// Set and Get the Widget.
+ void widget( Arts::Widget );
+ Arts::Widget widget();
+
+private:
+ std::string _name;
+ bool _lefttoright;
+ KPopupBox_widget *_widget;
+// KPopupBoxEventMapper *_mapper;
+
+}; // class KPopupBox
+
+} // namespace Arts
+
+#endif
+
+// vim: sw=4 ts=4
+
diff --git a/arts/gui/kde/kpopupbox_private.h b/arts/gui/kde/kpopupbox_private.h
new file mode 100644
index 00000000..b7e383d1
--- /dev/null
+++ b/arts/gui/kde/kpopupbox_private.h
@@ -0,0 +1,216 @@
+ /*
+
+ 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, 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.
+
+ */
+
+#ifndef KPOPUPBOX_PRIVATE_H
+#define KPOPUPBOX_PRIVATE_H
+
+
+class HandleDrag;
+class ShowButton;
+class OwnButton;
+class KArtsWidget;
+class OwnWidget;
+class QBoxLayout;
+
+#include <qframe.h>
+
+class KPopupBox_widget : public QFrame
+{
+ Q_OBJECT
+public:
+ KPopupBox_widget( QWidget* =0, const char* =0);
+ ~KPopupBox_widget();
+
+ Arts::Direction direction();
+ void direction( Arts::Direction );
+
+ void setWidget( Arts::Widget widget );
+ Arts::Widget getWidget();
+
+ void name( std::string );
+private slots:
+ void hide( bool );
+ void own( bool );
+private:
+ QBoxLayout *_layout;
+
+ QFrame *_titlebar;
+ QBoxLayout *_titlebarlayout;
+ HandleDrag *_drag;
+ ShowButton *_showbutton;
+ OwnButton *_ownbutton;
+
+ OwnWidget *_artswidget;
+};
+
+// See kpopupbox_impl.h - The eventmapper isn't needed at present, but perhaps in the future...
+
+/*class KPopupBoxEventMapper : public QObject {
+ Q_OBJECT
+public:
+ KPopupBoxEventMapper( KPopupBox_widget *widget, Arts::KPopupBox_impl *impl )
+ : QObject( widget,"" ), _widget( widget ), _impl( impl )
+ {}
+private:
+ KPopupBox_widget *_widget;
+ Arts::KPopupBox_impl *_impl;
+};*/
+
+#include <qpainter.h>
+#include <qstyle.h>
+
+class HandleDrag : public QWidget {
+ Q_OBJECT
+public:
+ HandleDrag( QWidget *parent, const char* name=0 ) : QWidget( parent,name ) {}
+ void paintEvent( QPaintEvent * ) {
+ QPainter p( this );
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if( width() < height() ) flags |= QStyle::Style_Horizontal;
+ style().drawPrimitive( QStyle::PE_DockWindowHandle, &p, rect(), colorGroup(), flags );
+ }
+signals:
+ void clicked();
+protected:
+ virtual void mouseDoubleClickEvent( QMouseEvent * ) {
+ emit clicked();
+ }
+};
+
+static const char* const close_xpm[] = { "5 5 2 1", "# c black", ". c None", "#...#", ".#.#.", "..#..", ".#.#.", "#...#"};
+static const char* const up_xpm[] = { "5 5 2 1", "# c black", ". c None", ".....", "..#..", ".###.", "#####", "....."};
+static const char* const down_xpm[] = { "5 5 2 1", "# c black", ". c None", ".....", "#####", ".###.", "..#..", "....."};
+static const char* const left_xpm[] = { "5 5 2 1", "# c black", ". c None", "...#.", "..##.", ".###.", "..##.", "...#."};
+static const char* const right_xpm[] = { "5 5 2 1", "# c black", ". c None", ".#...", ".##..", ".###.", ".##..", ".#..."};
+static const char* const inside_xpm[] = { "5 5 2 1", "# c black", ". c None", "#####", "#...#", "#...#", "#...#", "#####"};
+static const char* const own_xpm[] = { "5 5 2 1", "# c black", ". c None", "###..", "#.###", "###.#", ".#..#", ".####"};
+
+#include <qpushbutton.h>
+#include <qlayout.h>
+
+class ShowButton : public QPushButton {
+ Q_OBJECT
+private:
+ QBoxLayout::Direction _dir;
+ QPixmap _pmleft, _pmright, _pmup, _pmdown;
+public:
+ ShowButton( QWidget *parent, const char* name=0 ) : QPushButton( parent,name ), _dir( QBoxLayout::LeftToRight )
+ {
+ connect( this, SIGNAL( toggled( bool ) ), this, SLOT( owntoggle( bool ) ) );
+ setToggleButton( true );
+ _pmleft = QPixmap( const_cast<const char**>( left_xpm ) );
+ _pmright = QPixmap( const_cast<const char**>( right_xpm ) );
+ _pmup = QPixmap( const_cast<const char**>( up_xpm ) );
+ _pmdown = QPixmap( const_cast<const char**>( down_xpm ) );
+ setPixmap( _pmright );
+ }
+
+ void direction( QBoxLayout::Direction n ) { _dir=n; }
+public slots:
+ void owntoggle( bool b ) {
+ switch( _dir )
+ {
+ case QBoxLayout::BottomToTop:
+ if( b ) setPixmap( _pmdown );
+ else setPixmap( _pmup );
+ break;
+ case QBoxLayout::TopToBottom:
+ if( b ) setPixmap( _pmup );
+ else setPixmap( _pmdown );
+ break;
+ case QBoxLayout::LeftToRight:
+ if( b ) setPixmap( _pmright );
+ else setPixmap( _pmleft );
+ break;
+ case QBoxLayout::RightToLeft:
+ if( b ) setPixmap( _pmleft );
+ else setPixmap( _pmright );
+ break;
+ }
+ }
+public:
+ QSize minimumSizeHint() const {
+ int wh = style().pixelMetric( QStyle::PM_DockWindowHandleExtent, this );
+ return QSize( wh, wh );
+ }
+ QSizePolicy sizePolicy() const { return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); }
+ QSize minimumSize() const { return minimumSizeHint(); }
+ QSize sizeHint() const { return minimumSize(); }
+
+ void drawButton( QPainter * p )
+ {
+ p->fillRect( 0,0, width(), height(), QBrush( colorGroup().brush( QColorGroup::Background ) ) );
+ p->drawPixmap( ( width() - pixmap()->width() ) / 2, ( height() - pixmap()->height() ) / 2, *pixmap() );
+ }
+};
+
+class OwnButton : public QPushButton {
+ Q_OBJECT
+private:
+ QPixmap _pmown, _pminside;
+public:
+ OwnButton( QWidget *parent, const char* name=0 ) : QPushButton( parent,name )
+ {
+ connect( this, SIGNAL( toggled( bool ) ), this, SLOT( toggle( bool ) ) );
+ setToggleButton( true );
+ _pmown = QPixmap( const_cast<const char**>( own_xpm ) );
+ _pminside = QPixmap( const_cast<const char**>( inside_xpm ) );
+ setPixmap( _pmown );
+ }
+
+public slots:
+ void toggle( bool b ) {
+ if( b ) setPixmap( _pminside );
+ else setPixmap( _pmown );
+ }
+public:
+ QSize minimumSizeHint() const {
+ int wh = style().pixelMetric( QStyle::PM_DockWindowHandleExtent, this );
+ return QSize( wh, wh );
+ }
+ QSizePolicy sizePolicy() const { return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); }
+ QSize minimumSize() const { return minimumSizeHint(); }
+ QSize sizeHint() const { return minimumSize(); }
+
+ void drawButton( QPainter * p )
+ {
+ p->fillRect( 0,0, width(), height(), QBrush( colorGroup().brush( QColorGroup::Background ) ) );
+ p->drawPixmap( ( width() - pixmap()->width() ) / 2, ( height() - pixmap()->height() ) / 2, *pixmap() );
+ }
+};
+
+#include <kartswidget.h>
+
+class OwnWidget : public KArtsWidget
+{
+ Q_OBJECT
+ ShowButton *_b;
+public:
+ OwnWidget( ShowButton* b, QWidget* p, const char* n=0, WFlags f=0 ) : KArtsWidget( p,n,f ) { _b = b; }
+ ~OwnWidget() {}
+public slots:
+ void closeEvent( QCloseEvent * ) { _b->toggle(); }
+};
+
+#endif
+
+// vim: sw=4 ts=4
+
diff --git a/arts/gui/kde/kpoti.cpp b/arts/gui/kde/kpoti.cpp
new file mode 100644
index 00000000..e12c1bf5
--- /dev/null
+++ b/arts/gui/kde/kpoti.cpp
@@ -0,0 +1,780 @@
+/***************************************************************************
+ kpoti.cpp - potentiometer widget
+ -------------------
+ begin : Wed Apr 28 23:05:05 MEST 1999
+
+ copyright : (C) 1999 by Martin Lorenz
+ email : lorenz@ch.tum.de
+ (C) 2002-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. *
+ * *
+ ***************************************************************************/
+
+#include "kpoti.h"
+#include "kpoti.moc"
+
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qcolor.h>
+#include <qdrawutil.h>
+#include <qtimer.h>
+#include <qkeycode.h>
+#include <qpen.h>
+#include <qstring.h>
+#include <qstyle.h>
+
+#include <math.h>
+
+#include <kpixmap.h>
+#include <kpixmapeffect.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+#define PI 3.1415926
+static const int thresholdTime = 500;
+static const int repeatTime = 100;
+static const float maxAngle = PI*135/180; // 140 degrees to both sides
+static const float tickLength = 3;
+
+struct KPoti::KPotiPrivate
+{
+ KPotiPrivate()
+ : bgDirty( false )
+ , potiDirty( false )
+ {}
+
+ bool bgDirty;
+ KPixmap bgdb;
+ KPixmap bgPixmap( const QColorGroup & colorGroup )
+ {
+ if( bgDirty || bgdb.isNull() )
+ {
+ bgdb.resize( buttonRect.size() );
+ QPainter dbp( &bgdb );
+ dbp.setPen( Qt::NoPen );
+ QRect drawRect = bgdb.rect();
+
+ // create mask
+ QBitmap mask( bgdb.size(), true );
+ QPainter maskpainter( &mask );
+ maskpainter.setPen( Qt::NoPen );
+ maskpainter.setBrush( Qt::color1 );
+ maskpainter.drawEllipse( drawRect );
+ maskpainter.end();
+ bgdb.setMask( mask );
+
+ // inset shadow
+ KPixmap gradient( bgdb.size() );
+ KPixmapEffect::gradient( gradient, colorGroup.light(), colorGroup.dark(), KPixmapEffect::DiagonalGradient );
+ dbp.setBrush( QBrush( colorGroup.button(), gradient ) );
+ dbp.drawEllipse( drawRect );
+
+ potiRect.setSize( drawRect.size() * 0.9 );
+ if( potiRect.width() + 6 > drawRect.width() )
+ {
+ potiRect.setWidth( drawRect.width() - 6 );
+ potiRect.setHeight( drawRect.height() - 6 );
+ }
+ potiRect.moveCenter( center );
+
+ bgDirty = false;
+ }
+ return bgdb;
+ }
+
+ QColor potiColor;
+ bool potiDirty;
+ KPixmap potidb;
+ KPixmap potiPixmap()
+ {
+ if( ( potiDirty || potidb.isNull() ) && ! potiRect.size().isEmpty() )
+ {
+ potidb.resize( potiRect.size() );
+ QPainter dbp( &potidb );
+ dbp.setPen( Qt::NoPen );
+ QRect drawRect( potidb.rect() );
+
+ // create mask
+ QBitmap mask( potidb.size(), true );
+ QPainter maskpainter( &mask );
+ maskpainter.setPen( Qt::NoPen );
+ maskpainter.setBrush( Qt::color1 );
+ maskpainter.drawEllipse( drawRect );
+ maskpainter.end();
+ potidb.setMask( mask );
+
+ KPixmap gradient( potidb.size() );
+ KPixmapEffect::gradient( gradient, potiColor.dark( 130 ), potiColor.light( 130 ), KPixmapEffect::DiagonalGradient );
+ dbp.setBrush( QBrush( potiColor, gradient ) );
+ dbp.drawEllipse( drawRect );
+
+ potiDirty = false;
+ }
+ return potidb;
+ }
+
+ QRect buttonRect;
+ QRect potiRect;
+ QRect labelRect;
+ QString label;
+ QPoint center;
+};
+
+QSizePolicy KPoti::sizePolicy() const
+{
+ return QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
+}
+
+QSize KPoti::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+QSize KPoti::minimumSizeHint() const
+{
+ int width = 40;
+ int height = 40;
+ if( m_bLabel )
+ {
+ QFontMetrics metrics( font() );
+ d->labelRect = metrics.boundingRect( d->label );
+ d->labelRect.setHeight( metrics.lineSpacing() );
+ width = KMAX( width, d->labelRect.width() + frameRect().width() - contentsRect().width() );
+ height += metrics.lineSpacing();
+ }
+ //kdDebug() << k_funcinfo << "return " << width << "x" << height << endl;
+ return QSize( width, height );
+}
+
+QString KPoti::text() const
+{
+ return d->label;
+}
+
+void KPoti::setText( const QString & text )
+{
+ d->label = text;
+ setMinimumSize( minimumSizeHint() );
+ updateGeometry();
+}
+
+/**
+ Constructs a poti.
+
+ The \e parent and \e name arguments are sent to the QWidget constructor.
+*/
+KPoti::KPoti( QWidget *parent, const char *name )
+ : QFrame( parent, name, WResizeNoErase | WRepaintNoErase )
+ , d( 0 )
+{
+ init();
+}
+
+
+
+/**
+ Constructs a poti.
+
+ \arg \e minValue is the minimum slider value.
+ \arg \e maxValue is the maximum slider value.
+ \arg \e step is the page step value.
+ \arg \e value is the initial value.
+
+ The \e parent and \e name arguments are sent to the QWidget constructor.
+*/
+
+KPoti::KPoti( int minValue, int maxValue, int step,
+ int value, QWidget *parent, const char *name )
+ : QFrame( parent, name, WResizeNoErase | WRepaintNoErase )
+ , QRangeControl( minValue, maxValue, 1, step, value )
+ , d( 0 )
+{
+ init(value);
+}
+
+KPoti::~KPoti()
+{
+ delete d;
+ d = 0;
+}
+
+void KPoti::init(int value)
+{
+ d = new KPotiPrivate;
+ font().setPointSize( 8 );
+ d->potiColor.setNamedColor( "red" );
+
+ timer = 0;
+ potiVal = value;
+ potiPos = positionFromValue(value);
+ clickOffset = 0;
+ state = Idle;
+ track = TRUE;
+ ticks = TRUE;
+ m_bLabel = true;
+ tickInt = 0;
+
+ setFocusPolicy( TabFocus );
+ initTicks();
+}
+
+
+/**
+ Does what's needed when someone changes the tickmark status
+*/
+
+void KPoti::initTicks()
+{
+ QRect available = contentsRect();
+ if( m_bLabel )
+ available.rTop() += d->labelRect.height();
+ d->center = available.center();
+ // make the width and height equal
+ if( available.width() > available.height() )
+ available.setWidth( available.height() );
+ else if( available.height() > available.width() )
+ available.setHeight( available.width() );
+ available.moveCenter( d->center );
+ d->buttonRect = available;
+
+ buttonRadius = available.width() / 2.0;
+ if( ticks )
+ {
+ buttonRadius -= tickLength;
+ int tickSpace = static_cast<int>( tickLength );
+ d->buttonRect.rTop() += tickSpace;
+ d->buttonRect.rLeft() += tickSpace;
+ d->buttonRect.rRight() -= tickSpace;
+ d->buttonRect.rBottom() -= tickSpace;
+ }
+
+ d->potiDirty = true;
+ d->bgDirty = true;
+}
+
+
+/**
+ Enables slider tracking if \e enable is TRUE, or disables tracking
+ if \e enable is FALSE.
+
+ If tracking is enabled (default), the slider emits the
+ valueChanged() signal whenever the slider is being dragged. If
+ tracking is disabled, the slider emits the valueChanged() signal
+ when the user releases the mouse button (unless the value happens to
+ be the same as before).
+
+ \sa tracking()
+*/
+
+void KPoti::setTracking( bool enable )
+{
+ track = enable;
+}
+
+
+/**
+ \fn bool KPoti::tracking() const
+ Returns TRUE if tracking is enabled, or FALSE if tracking is disabled.
+
+ Tracking is initially enabled.
+
+ \sa setTracking()
+*/
+
+
+/**
+ \fn void KPoti::valueChanged( int value )
+ This signal is emitted when the slider value is changed, with the
+ new slider value as an argument.
+*/
+
+/**
+ \fn void KPoti::sliderPressed()
+ This signal is emitted when the user presses the slider with the mouse.
+*/
+
+/**
+ \fn void KPoti::sliderMoved( int value )
+ This signal is emitted when the slider is dragged, with the
+ new slider value as an argument.
+*/
+
+/**
+ \fn void KPoti::sliderReleased()
+ This signal is emitted when the user releases the slider with the mouse.
+*/
+
+/**
+ Calculates slider position corresponding to value \a v. Does not perform
+ rounding.
+*/
+
+float KPoti::positionFromValue( int v ) const
+{
+
+ int range = maxValue() - minValue();
+ return ( (v - minValue() ) *2* maxAngle) / range - maxAngle;
+}
+
+
+/**
+ Calculates value corresponding to poti position \a p. Performs rounding.
+*/
+
+int KPoti::valueFromPosition( float p ) const
+{
+ int range = maxValue() - minValue();
+ return (int) (minValue() + ((p+maxAngle)*range)/(2*maxAngle));
+}
+
+/*!
+ Implements the virtual QRangeControl function.
+*/
+
+void KPoti::rangeChange()
+{
+ float newPos = positionFromValue( value() );
+ if ( newPos != potiPos ) {
+ reallyMovePoti( newPos );
+ }
+}
+
+void KPoti::paletteChange( const QPalette & )
+{
+ d->bgDirty = true;
+ d->potiDirty = true;
+}
+
+/*!
+ Changes the value (slot)
+*/
+
+void KPoti::valueChange()
+{
+ if ( potiVal != value() ) {
+ float newPos = positionFromValue( value() );
+ potiVal = value();
+ reallyMovePoti( newPos );
+ }
+ emit valueChanged(value());
+}
+
+
+/*!
+ Handles resize events for the poti.
+*/
+
+void KPoti::resizeEvent( QResizeEvent * )
+{
+ rangeChange();
+ initTicks();
+}
+
+void KPoti::setLabel(bool s)
+{
+ m_bLabel = s;
+ initTicks();
+}
+
+/**
+ Sets the color of the button
+ */
+void KPoti::setColor( const QColor &c )
+{
+ d->potiColor = c;
+ d->potiDirty = true;
+ repaint();
+}
+
+
+void KPoti::paintPoti( QPainter * p )
+{
+ if( isVisible() )
+ {
+ KPixmap db = d->potiPixmap();
+ if( db.isNull() )
+ return;
+
+ QPainter p2( &db );
+ p2.translate( db.rect().center().x(), db.rect().center().y() );
+ p2.rotate( potiPos * 180.0 / PI );
+ QRect pointer( db.width() / -20, db.width() / -2, db.width() / 10, db.width() / 2 );
+ QBrush buttonbrush( colorGroup().button() );
+ qDrawShadePanel( &p2, pointer, colorGroup(), true, 1, &buttonbrush );
+ p2.end();
+
+ p->drawPixmap( d->potiRect, db );
+ }
+}
+
+/*!
+ Performs the actual moving of the slider.
+*/
+
+void KPoti::reallyMovePoti( float newPos )
+{
+ QPainter p;
+ p.begin( this );
+ p.setPen(NoPen);
+ potiPos = newPos;
+ paintPoti(&p);
+ p.end();
+}
+
+
+
+
+/**
+ Handles paint events for the slider.
+*/
+
+void KPoti::drawContents( QPainter * p )
+{
+ QPixmap doublebuffer( contentsRect().size() );
+ doublebuffer.fill( colorGroup().background() );
+ QPainter dbp( &doublebuffer );
+ if( m_bLabel )
+ {
+ dbp.setFont( font() );
+ QFontMetrics metrics = dbp.fontMetrics();
+ dbp.drawText( contentsRect().x() - metrics.leftBearing( d->label[ 0 ] ) + ( contentsRect().width() - d->labelRect.width() ) / 2, metrics.height(), d->label );
+ }
+
+ int interval = tickInt;
+ if( interval <= 0 )
+ interval = 12;
+ if( ticks )
+ drawTicks( &dbp, buttonRadius, tickLength, interval );
+
+ dbp.drawPixmap( d->buttonRect, d->bgPixmap( colorGroup() ) );
+
+ if( hasFocus() )
+ style().drawPrimitive( QStyle::PE_FocusRect, &dbp, d->buttonRect, colorGroup() );
+
+ paintPoti( &dbp );
+ dbp.end();
+ p->drawPixmap( contentsRect(), doublebuffer );
+}
+
+
+/*!
+ Handles mouse press events for the slider.
+*/
+
+void KPoti::mousePressEvent( QMouseEvent *e )
+{
+ resetState();
+
+ if ( e->button() == MidButton ) {
+ double pos = atan2( double(e->pos().x()-d->center.x()),
+ double(- e->pos().y() + d->center.y()) );
+ movePoti( pos );
+ return;
+ }
+ if ( e->button() != LeftButton )
+ return;
+
+
+ int dx=e->pos().x()-d->center.x(), dy=e->pos().y()-d->center.y();
+
+ if ( dx*dx+dy*dy < buttonRadius*buttonRadius ) {
+ state = Dragging;
+ clickOffset = potiVal + (e->pos().y() ) ;
+ emit potiPressed();
+ } else if ( e->pos().x() < width()/2 ) {
+ state = TimingDown;
+ subtractPage();
+ if ( !timer )
+ timer = new QTimer( this );
+ connect( timer, SIGNAL(timeout()), SLOT(repeatTimeout()) );
+ timer->start( thresholdTime, TRUE );
+ } else {
+ state = TimingUp;
+ addPage();
+ if ( !timer )
+ timer = new QTimer( this );
+ connect( timer, SIGNAL(timeout()), SLOT(repeatTimeout()) );
+ timer->start( thresholdTime, TRUE );
+ }
+}
+
+/*!
+ Handles mouse move events for the slider.
+*/
+void KPoti::mouseMoveEvent( QMouseEvent *e )
+{
+
+ if ( (e->state() & MidButton) ) { // middle button wins
+ double pos = atan2( double(e->pos().x()-d->center.x()),
+ double(- e->pos().y()+d->center.y()) );
+ movePoti( pos );
+ return;
+ }
+ if ( !(e->state() & LeftButton) )
+ return; // left mouse button is up
+ if ( state != Dragging )
+ return;
+
+
+ movePoti( positionFromValue(- e->pos().y() + clickOffset ));
+}
+
+
+/*!
+ Handles mouse release events for the slider.
+*/
+
+void KPoti::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( !(e->button() & LeftButton) )
+ return;
+ resetState();
+}
+
+void KPoti::focusInEvent( QFocusEvent * e )
+{
+ //setFrameStyle( Raised | Box );
+ //setLineWidth( 1 );
+ QFrame::focusInEvent( e );
+}
+
+void KPoti::focusOutEvent( QFocusEvent * e )
+{
+ //setFrameStyle( NoFrame );
+ //setLineWidth( 0 );
+ QFrame::focusOutEvent( e );
+}
+
+
+void KPoti::enterEvent( QEvent * )
+{
+ emit mouseEntered( potiVal );
+}
+
+
+/*!
+ Moves the left (or top) edge of the slider to position
+ \a pos. Performs snapping.
+*/
+
+void KPoti::movePoti( float pos )
+{
+ float newPos = QMIN( maxAngle, QMAX( -maxAngle, pos ) );
+ int newVal = valueFromPosition( newPos );
+ if ( potiVal != newVal ) {
+ potiVal = newVal;
+ emit potiMoved( potiVal );
+ }
+ if ( tracking() && potiVal != value() ) {
+ directSetValue( potiVal );
+ emit valueChanged( potiVal );
+ }
+
+
+ if ( potiPos != newPos )
+ reallyMovePoti( newPos );
+}
+
+
+/*!
+ Resets all state information and stops my timer.
+*/
+
+void KPoti::resetState()
+{
+ if ( timer ) {
+ timer->stop();
+ timer->disconnect();
+ }
+ switch ( state ) {
+ case TimingUp:
+ case TimingDown:
+ break;
+ case Dragging: {
+ setValue( valueFromPosition( potiPos ) );
+ emit potiReleased();
+ break;
+ }
+ case Idle:
+ break;
+ default:
+ kdWarning() << "KPoti: in wrong state" << endl;
+ }
+ state = Idle;
+}
+
+
+/*!
+ Handles key press events for the slider.
+*/
+
+void KPoti::keyPressEvent( QKeyEvent *e )
+{
+
+ switch ( e->key() ) {
+ case Key_Left:
+ subtractLine();
+ break;
+ case Key_Right:
+ addLine();
+ break;
+ case Key_Up:
+ addLine();
+ break;
+ case Key_Down:
+ subtractLine();
+ break;
+ case Key_Prior:
+ subtractPage();
+ break;
+ case Key_Next:
+ addPage();
+ break;
+ case Key_Home:
+ setValue( minValue() );
+ break;
+ case Key_End:
+ setValue( maxValue() );
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ e->accept();
+}
+
+
+
+
+
+/*!
+ Makes QRangeControl::setValue() available as a slot.
+*/
+
+void KPoti::setValue( int value )
+{
+ QRangeControl::setValue( value );
+}
+
+
+/*!
+ Moves the slider one pageStep() upwards.
+*/
+
+void KPoti::addStep()
+{
+ addPage();
+}
+
+
+/*!
+ Moves the slider one pageStep() downwards.
+*/
+
+void KPoti::subtractStep()
+{
+ subtractPage();
+}
+
+
+/*!
+ Waits for autorepeat.
+*/
+
+void KPoti::repeatTimeout()
+{
+ Q_ASSERT( timer );
+ timer->disconnect();
+ if ( state == TimingDown )
+ connect( timer, SIGNAL(timeout()), SLOT(subtractStep()) );
+ else if ( state == TimingUp )
+ connect( timer, SIGNAL(timeout()), SLOT(addStep()) );
+ timer->start( repeatTime, FALSE );
+}
+
+
+
+
+/*!
+ Using \a p, draws tickmarks at a distance of \a dist from the edge
+ of the widget, using \a w pixels and \a i intervals.
+ */
+
+void KPoti::drawTicks( QPainter *p, double dist, double w, int i ) const
+{
+ p->setPen( colorGroup().foreground() );
+ double angle,s,c;
+ double x, y;
+ for (int v=0; v<=i; v++)
+ {
+ angle = -maxAngle+2*maxAngle*v/i;
+ s = sin( angle );
+ c = cos( angle );
+ x = d->center.x() - s * dist;
+ y = d->center.y() - c * dist;
+
+ p->drawLine( (int)x, (int)y, (int)(x - s * w), (int)(y - c * w) );
+ }
+}
+
+void KPoti::wheelEvent(QWheelEvent *e)
+{
+ setValue(value()+e->delta()/120*8);
+}
+
+
+/*!
+ Sets the way tickmarks are displayed by the slider. \a s can take
+ the following values:
+ <ul>
+ <li> \c NoMarks
+ <li> \c Above
+ <li> \c Left
+ <li> \c Below
+ <li> \c Right
+ <li> \c Both
+ </ul>
+ The initial value is \c NoMarks.
+ \sa tickmarks(), setTickInterval()
+*/
+
+void KPoti::setTickmarks( bool s )
+{
+ ticks = s;
+ initTicks();
+ update();
+}
+
+
+
+/*!
+ Sets the interval between tickmarks to \a i. This is a value interval,
+ not a pixel interval. If \a i is 0, the slider
+ will choose between lineStep() and pageStep(). The initial value of
+ tickInterval() is 0.
+ \sa tickInterval(), QRangeControl::lineStep(), QRangeControl::pageStep()
+*/
+
+void KPoti::setTickInterval( int i )
+{
+ tickInt = QMAX( 0, i );
+ update();
+}
+
+
+/*!
+ \fn int KPoti::tickInterval() const
+ Returns the interval between tickmarks. Returns 0 if the slider
+ chooses between pageStep() and lineStep().
+ \sa setTickInterval()
+*/
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kpoti.h b/arts/gui/kde/kpoti.h
new file mode 100644
index 00000000..a87b5162
--- /dev/null
+++ b/arts/gui/kde/kpoti.h
@@ -0,0 +1,136 @@
+/***************************************************************************
+ kpoti.h - Potentiometer Widget
+ -------------------
+ begin : Wed Apr 28 23:05:05 MEST 1999
+
+ copyright : (C) 1999 by Martin Lorenz
+ email : lorenz@ch.tum.de
+ (C) 2002 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef _KPOTI_H
+#define _KPOTI_H
+
+#include <qframe.h>
+#include <qrangecontrol.h>
+
+
+class QTimer;
+struct QPotiData;
+
+
+class KPoti : public QFrame, public QRangeControl
+{
+ Q_OBJECT
+public:
+
+ KPoti( QWidget *parent=0, const char *name=0 );
+ KPoti( int minValue, int maxValue, int step, int value,
+ QWidget *parent=0, const char *name=0 );
+
+ ~KPoti();
+
+ void setTracking( bool enable );
+ bool tracking() const;
+
+ void setColor( const QColor & );
+
+ virtual void setTickmarks( bool );
+ virtual void setLabel( bool );
+ bool tickmarks() const { return ticks; }
+
+ virtual void setTickInterval( int );
+ int tickInterval() const { return tickInt; }
+
+ virtual QSizePolicy sizePolicy() const;
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+ QString text() const;
+
+public slots:
+ void setValue( int );
+ void addStep();
+ void subtractStep();
+ void setText( const QString & );
+
+signals:
+ void valueChanged( int value );
+ void potiPressed();
+ void potiMoved( int value );
+ void potiReleased();
+ void mouseEntered(int value);
+
+protected:
+ void resizeEvent( QResizeEvent * );
+ void drawContents( QPainter * );
+
+ void keyPressEvent( QKeyEvent * );
+
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void enterEvent( QEvent *);
+
+ void focusInEvent( QFocusEvent *e );
+ void focusOutEvent( QFocusEvent *e );
+
+ void valueChange();
+ void rangeChange();
+
+ virtual void paletteChange( const QPalette & );
+
+ virtual void paintPoti( QPainter * );
+ void drawButton( QPainter *);
+ void drawTicks( QPainter *, double, double, int=1 ) const;
+
+ virtual void wheelEvent(QWheelEvent *e);
+private slots:
+ void repeatTimeout();
+
+private:
+ enum State { Idle, Dragging, TimingUp, TimingDown };
+
+ void init(int value=0);
+ float positionFromValue( int ) const;
+ int valueFromPosition( float ) const;
+ void movePoti( float );
+ void reallyMovePoti( float );
+ void resetState();
+ int potiRadius() const;
+ void initTicks();
+
+ QTimer *timer;
+ float potiPos;
+ int potiVal;
+ int clickOffset;
+ State state;
+ bool track;
+ bool ticks, m_bLabel;
+ int tickInt, space;
+ double buttonRadius;
+private: // Disabled copy constructor and operator=
+ // KPoti( const KPoti & ) {}
+ //KPoti &operator=( const KPoti & ) { return *this; }
+ struct KPotiPrivate;
+ KPotiPrivate * d;
+};
+
+inline bool KPoti::tracking() const
+{
+ return track;
+}
+
+
+#endif // _KPOTI_H
+
+
+
diff --git a/arts/gui/kde/kpoti_impl.cpp b/arts/gui/kde/kpoti_impl.cpp
new file mode 100644
index 00000000..10b0adb3
--- /dev/null
+++ b/arts/gui/kde/kpoti_impl.cpp
@@ -0,0 +1,203 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 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 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 "kpoti_impl.h"
+#include "kpoti_impl.moc"
+#include "anyref.h"
+#include "stdio.h"
+
+#include <math.h>
+
+using namespace Arts;
+using namespace std;
+
+PotiIntMapper::PotiIntMapper(KPoti_impl *impl, KPoti *kp)
+ : QObject( kp )
+ , impl( impl )
+{
+ connect(kp, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
+}
+
+void PotiIntMapper::valueChanged(int pos)
+{
+ impl->valueChanged(pos);
+}
+
+KPoti_impl::KPoti_impl( KPoti * widget )
+ : KFrame_impl( widget ? widget : new KPoti( 0, 100, 1, 0 ) )
+{
+ _min = 0; _max = 1; _value = 0;
+ _factor = 1;
+ _logarithmic = 0;
+ _range = 100;
+
+ _kpoti = static_cast<KPoti*>( _qwidget );
+ ( void )new PotiIntMapper( this, _kpoti );
+}
+
+string KPoti_impl::caption()
+{
+ return _kpoti->text().utf8().data();
+}
+
+void KPoti_impl::caption(const string& newText)
+{
+ _caption = QString::fromUtf8( newText.c_str() );
+ _kpoti->setText( _caption );
+}
+
+string KPoti_impl::color()
+{
+ return _color;
+}
+
+void KPoti_impl::color(const string& newColor)
+{
+ _color = newColor;
+ if(strlen(_color.c_str()))
+ {
+ QColor qc(_color.c_str());
+ _kpoti->setColor(qc);
+ }
+}
+
+float KPoti_impl::min()
+{
+ return _min;
+}
+
+void KPoti_impl::min(float newMin)
+{
+ if(_min != newMin)
+ {
+ _min = newMin;
+ applyValue();
+ }
+}
+
+float KPoti_impl::max()
+{
+ return _max;
+}
+
+void KPoti_impl::max(float newMax)
+{
+ if(_max != newMax)
+ {
+ _max = newMax;
+ applyValue();
+ }
+}
+
+float KPoti_impl::value()
+{
+ float ret = float(_kpoti->value()) / _factor;
+ if(_logarithmic > 0)
+ ret = convertFromLog(ret);
+ if(ret < _min)
+ ret = _min;
+ else if(ret > _max)
+ ret = _max;
+ return ret;
+}
+
+void KPoti_impl::value(float newValue)
+{
+ if(newValue != _value)
+ {
+ _value = newValue;
+ applyValue();
+ if(visible())
+ value_changed(value());
+ }
+}
+
+long KPoti_impl::range()
+{
+ return _range;
+}
+
+void KPoti_impl::range(long newRange)
+{
+ if(_range != newRange)
+ {
+ _range = newRange;
+ applyValue();
+ }
+}
+
+void KPoti_impl::valueChanged(int newvalue)
+{
+ _value = (float)newvalue / _factor;
+ if(_logarithmic > 0)
+ _value = convertFromLog(_value);
+ if(visible())
+ value_changed(value());
+}
+
+float KPoti_impl::convertToLog(float val)
+{
+ return log(val) / log(_logarithmic);
+}
+
+float KPoti_impl::convertFromLog(float val)
+{
+ return pow(_logarithmic, val);
+}
+
+void KPoti_impl::applyValue()
+{
+ double dmin = _min;
+ double dmax = _max;
+ double dvalue = _value;
+ if(_logarithmic > 0)
+ {
+ dmin = convertToLog(_min);
+ dmax = convertToLog(_max);
+ dvalue = convertToLog(_value);
+ }
+ _factor = _range / (dmax - dmin);
+ int imin = int(_factor * dmin);
+ int imax = int(_factor * dmax);
+ int ivalue = int(_factor * dvalue);
+ _kpoti->setRange(imin, imax);
+ _kpoti->setValue(ivalue);
+}
+
+void KPoti_impl::logarithmic(float newLogarithmic)
+{
+ if(_logarithmic != newLogarithmic)
+ {
+ _logarithmic = newLogarithmic;
+ applyValue();
+ }
+}
+
+float KPoti_impl::logarithmic()
+{
+ return _logarithmic;
+}
+
+REGISTER_IMPLEMENTATION(KPoti_impl);
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kpoti_impl.h b/arts/gui/kde/kpoti_impl.h
new file mode 100644
index 00000000..94b03a6f
--- /dev/null
+++ b/arts/gui/kde/kpoti_impl.h
@@ -0,0 +1,90 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 2001, 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 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.
+
+ */
+
+#ifndef ARTS_GUI_KPOTI_IMPL_H
+#define ARTS_GUI_KPOTI_IMPL_H
+#include "kframe_impl.h"
+#include "kpoti.h"
+
+#include <qobject.h>
+#include <qstring.h>
+
+
+namespace Arts {
+
+class KPoti_impl;
+
+class PotiIntMapper :public QObject {
+ Q_OBJECT
+ KPoti_impl *impl;
+public:
+ PotiIntMapper(KPoti_impl *impl, KPoti *kp);
+public slots:
+ void valueChanged(int x);
+};
+
+class KPoti_impl : virtual public Arts::Poti_skel,
+ public Arts::KFrame_impl
+{
+protected:
+ KPoti * _kpoti;
+ QString _caption;
+ std::string _color;
+ float _min, _max, _value;
+ float _factor;
+ float _logarithmic;
+ long _range;
+
+ float convertToLog(float);
+ float convertFromLog(float);
+ void applyValue();
+
+public:
+ KPoti_impl( KPoti * w = 0 );
+
+ std::string caption();
+ void caption(const std::string& newText);
+ std::string color();
+ void color(const std::string& newColor);
+
+ float logarithmic();
+ void logarithmic(float);
+
+ float min();
+ void min(float newMin);
+ float max();
+ void max(float newMax);
+ float value();
+ void value(float newValue);
+
+ long range();
+ void range(long newRange);
+
+ /* from qt */
+ void valueChanged(int newValue);
+};
+
+}
+#endif /* ARTS_GUI_KPOTI_IMPL_H */
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kspinbox_impl.cpp b/arts/gui/kde/kspinbox_impl.cpp
new file mode 100644
index 00000000..f97716c4
--- /dev/null
+++ b/arts/gui/kde/kspinbox_impl.cpp
@@ -0,0 +1,108 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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 "kspinbox_impl.h"
+#include "kspinbox_impl.moc"
+#include "anyref.h"
+#include "stdio.h"
+
+using namespace Arts;
+using namespace std;
+
+SpinBoxIntMapper::SpinBoxIntMapper(KSpinBox_impl *impl, QSpinBox *sp)
+ :impl(impl)
+{
+ connect(sp, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
+}
+
+void SpinBoxIntMapper::valueChanged(int pos)
+{
+ impl->valueChanged(pos);
+}
+
+KSpinBox_impl::KSpinBox_impl( QSpinBox * widget )
+ : KWidget_impl( widget ? widget : new QSpinBox )
+{
+ _min = 0; _max = 100; _value = 0;
+ _qspinbox = static_cast<QSpinBox*>( _qwidget );
+ _qspinbox->setRange( 0, 100 );
+ ( void )new SpinBoxIntMapper( this, _qspinbox );
+}
+
+string KSpinBox_impl::caption()
+{
+ return _caption.utf8().data();
+}
+
+void KSpinBox_impl::caption(const string& newCaption)
+{
+ _caption = QString::fromUtf8(newCaption.c_str());
+ // FIXME: do something with the caption here
+}
+
+long KSpinBox_impl::min()
+{
+ return _min;
+}
+
+void KSpinBox_impl::min(long newMin)
+{
+ _min = newMin;
+ _qspinbox->setMinValue(newMin);
+}
+
+long KSpinBox_impl::max()
+{
+ return _max;
+}
+
+void KSpinBox_impl::max(long newMax)
+{
+ _max = newMax;
+ _qspinbox->setMaxValue(newMax);
+}
+
+long KSpinBox_impl::value()
+{
+ return _value;
+}
+
+void KSpinBox_impl::value(long newValue)
+{
+ if(newValue != _value)
+ {
+ _value = newValue;
+ _qspinbox->setValue(newValue);
+ if(visible())
+ value_changed(newValue);
+ }
+}
+
+void KSpinBox_impl::valueChanged(int newvalue)
+{
+ value(newvalue);
+}
+
+REGISTER_IMPLEMENTATION(KSpinBox_impl);
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kspinbox_impl.h b/arts/gui/kde/kspinbox_impl.h
new file mode 100644
index 00000000..b0af8bae
--- /dev/null
+++ b/arts/gui/kde/kspinbox_impl.h
@@ -0,0 +1,76 @@
+ /*
+
+ Copyright (C) 2000,2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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.
+
+ */
+
+#ifndef ARTS_GUI_KSPINBOX_IMPL_H
+#define ARTS_GUI_KSPINBOX_IMPL_H
+#include "kwidget_impl.h"
+
+#include <qspinbox.h>
+#include <qobject.h>
+#include <qstring.h>
+
+
+namespace Arts {
+
+class KSpinBox_impl;
+class SpinBoxIntMapper :public QObject {
+ Q_OBJECT
+ KSpinBox_impl *impl;
+public:
+ SpinBoxIntMapper(KSpinBox_impl *impl, QSpinBox *sp);
+public slots:
+ void valueChanged(int x);
+};
+
+class KSpinBox_impl : virtual public Arts::SpinBox_skel,
+ public Arts::KWidget_impl
+{
+protected:
+ QSpinBox * _qspinbox;
+ QString _caption;
+ long _min, _max, _value;
+
+ void applyValue();
+
+public:
+ KSpinBox_impl( QSpinBox * w = 0 );
+ void constructor( Widget p ) { parent( p ); }
+
+ std::string caption();
+ void caption(const std::string& newCaption);
+
+ long min();
+ void min(long newMin);
+ long max();
+ void max(long newMax);
+ long value();
+ void value(long newValue);
+
+ /* from qt */
+ void valueChanged(int newValue);
+};
+
+}
+#endif /* ARTS_GUI_KSPINBOX_IMPL_H */
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/ktickmarks_impl.cpp b/arts/gui/kde/ktickmarks_impl.cpp
new file mode 100644
index 00000000..0aa0a01e
--- /dev/null
+++ b/arts/gui/kde/ktickmarks_impl.cpp
@@ -0,0 +1,179 @@
+/*
+ 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 "ktickmarks_impl.h"
+
+#include <kdebug.h>
+#include <qpainter.h>
+#include <qfont.h>
+#include <qfontmetrics.h>
+
+KTickmarks_impl::KTickmarks_impl( QFrame* w ) : Arts::KFrame_impl( w ? w : new KTickmarks_Widget( 0 ) )
+{
+ //kdDebug()<<"KTickmarks_impl::KTickmarks_impl( QFrame* w="<<w<<" )"<<endl;
+ _tmwidget = static_cast<KTickmarks_Widget*>( _qwidget );
+}
+
+float KTickmarks_impl::min() { return _tmwidget->dbmin; }
+void KTickmarks_impl::min( float n ) { _tmwidget->dbmin = n; }
+float KTickmarks_impl::max() { return _tmwidget->dbmax; }
+void KTickmarks_impl::max( float n ) { _tmwidget->dbmax = n; }
+float KTickmarks_impl::minstep() { return _tmwidget->minstep; }
+void KTickmarks_impl::minstep( float n ) { _tmwidget->minstep = n; }
+float KTickmarks_impl::substep() { return _tmwidget->substep; }
+void KTickmarks_impl::substep( float n ) { _tmwidget->substep = n; }
+
+Arts::Direction KTickmarks_impl::direction() { return _tmwidget->_dir; }
+void KTickmarks_impl::direction( Arts::Direction n ) { _tmwidget->_dir = n; }
+
+long KTickmarks_impl::position() { return _tmwidget->_pos; }
+void KTickmarks_impl::position( long n ) { _tmwidget->_pos = n; }
+
+void KTickmarks_impl::constructor( float min, float max, Arts::Direction dir, long pos ) {
+ this->min( min ); this->max( max ); direction( dir ); position( pos );
+}
+
+KTickmarks_Widget::KTickmarks_Widget( KTickmarks_impl* impl, QWidget* p, const char* n ) : QFrame( p,n ), dB2VolCalc( -24, 0 ), _impl( impl ), _pos( Arts::posLeft ), _dir( Arts::BottomToTop ), minstep( 1 ), substep( 0.5 ) {
+ setMinimumSize( 20,20 );
+}
+
+void KTickmarks_Widget::drawContents( QPainter* p ) {
+ //kdDebug()<<"KTickmarks::drawContents( QPainter* "<<p<<" )"<<endl;
+ bool left=false, right=false;
+ if ( _pos&Arts::posLeft ) left=true;
+ if ( _pos&Arts::posRight ) right=true;
+ // Setting the font
+ QFont font;
+ font.setPixelSize( 8 /*font.pixelSize()/2*/ ); // Maybe this could be adjusted...
+ p->setFont( font );
+ // Determining the size of the largest text (currently the text at the minimum-scale)
+ QFontMetrics fontmetric( font );
+ QRect fontrect = fontmetric.boundingRect( QString::number( dbmin ) );
+ // Calculating stepsizes
+ float _minstepcount = ( dbmax-dbmin )/minstep;
+ float _minstep = minstep; // this value gets changed
+ float _substepcount = ( dbmax-dbmin )/substep;
+ float _substep = substep; // this value gets changed
+ // Calculating minimum size of the widget
+ int _minsize;
+ // Shorcuts
+ int w,h;
+ QColor colornormal = colorGroup().foreground();
+ QColor colordiff = colorGroup().buttonText();
+
+ if ( _dir == Arts::BottomToTop || _dir == Arts::TopToBottom ) {
+ p->translate( contentsRect().left(), contentsRect().bottom() );
+ // Calculating stepsizes
+ for ( int i=1; _minstepcount*( fontrect.height()+4 ) > contentsRect().height(); i++ ) {
+ _minstepcount = ( dbmax-dbmin ) / minstep / i;
+ _minstep = minstep*i;
+ }
+ while ( _substepcount*2 > contentsRect().height() ) { _substepcount/=2; _substep*=2; }
+ // Calculating minimum size of the widget
+ _minsize=fontrect.width()+4;
+ if ( left ) _minsize+=6;
+ if ( right ) _minsize+=6;
+ setMinimumWidth( _minsize + frameWidth() + 2 );
+// setMaximumWidth( _minsize /*+6*/ );
+ w = contentsRect().width(); // Just a shortcut
+ h=0;
+ // Painting substep marks
+ p->setPen( QPen( colordiff, 1 ) );
+ for ( float i=dbmax; i>=dbmin; i-=_substep ) {
+ h = int( -contentsRect().height() * dbtondb( i ) );
+ if ( _dir==Arts::TopToBottom ) h = 1 - h;
+ if ( left ) p->drawLine( 0, h, 3, h );
+ if ( right ) p->drawLine( w-3, h, w, h );
+ }
+ // Painting step marks and texts
+ p->setPen( QPen( colornormal, 1 ) );
+ for ( float i=0; i>=dbmin; i-=_minstep ) {
+ h = int( -contentsRect().height() * dbtondb( i ) );
+ if ( _dir==Arts::TopToBottom ) h = 1 - h;
+ if ( left ) p->drawLine( 0, h, 6, h );
+ p->drawText( ( w - (left)*6 - (right)*6 - fontrect.width() )/2 + (left)*6
+ , h-fontrect.height()/2,
+ fontrect.width(), fontrect.height()+2,
+ Qt::AlignRight|Qt::AlignTop, QString::number( i ) );
+ if ( right ) p->drawLine( w-6, h, w, h );
+ }
+ for ( float i=_minstep; i<=dbmax; i+=_minstep ) {
+ h = int( -contentsRect().height() * dbtondb( i ) );
+ if ( _dir==Arts::TopToBottom ) h = 1 - h;
+ if ( left ) p->drawLine( 0, h, 6, h );
+ p->drawText( ( w - (left)*6 - (right)*6 - fontrect.width() )/2 + (left)*6
+ , h-fontrect.height()/2,
+ fontrect.width(), fontrect.height()+2,
+ Qt::AlignRight|Qt::AlignTop, QString::number( i ) );
+ if ( right ) p->drawLine( w-6, h, w, h );
+ }
+ } else {
+ //if ( _dir == Arts::LeftToRight || _dir == Arts::RightToLeft ) {
+ // Calculating stepsizes
+ for ( int i=1; _minstepcount*( fontrect.width()+4 ) > contentsRect().width(); i++ ) {
+ _minstepcount = ( dbmax-dbmin ) / minstep / i;
+ _minstep = minstep*i;
+ }
+ while ( _substepcount*2 > contentsRect().width() ) { _substepcount/=2; _substep*=2; }
+ // Calculating minimum size of the widget
+ _minsize=fontrect.height()+4;
+ if ( left ) _minsize+=6;
+ if ( right ) _minsize+=6;
+ setMinimumHeight( _minsize + frameWidth() + 2 );
+// setMaximumHeight( _minsize /*+6*/ );
+ w = 0; // Just a shortcut
+ h = frameWidth() + contentsRect().height();
+ // Painting substep marks
+ p->setPen( QPen( colordiff, 1 ) );
+ for ( float i=dbmax; i>=dbmin; i-=_substep ) {
+ w = this->frameWidth()+ int( contentsRect().width() * dbtondb( i ) );
+ if ( _dir==Arts::RightToLeft ) w = 1 - w;
+ if ( left ) p->drawLine( w, frameWidth(), w, frameWidth() + 3 );
+ if ( right ) p->drawLine( w, h-3, w, h );
+ }
+ // Painting step marks and texts
+ p->setPen( QPen( colornormal, 1 ) );
+ for ( float i=0; i>=dbmin; i-=_minstep ) {
+ w = int( contentsRect().width() * dbtondb( i ) );
+ if ( _dir==Arts::RightToLeft ) w = 1 - w;
+ if ( left ) p->drawLine( w, 0, w, 6 );
+ p->drawText( w - fontrect.width()/2
+ , ( h - (left)*6 - (right)*6 - fontrect.height() )/2 + (left)*6,
+ fontrect.width(), fontrect.height()+2,
+ Qt::AlignRight|Qt::AlignTop, QString::number( i ) );
+ if ( right ) p->drawLine( w, h-6, w, h );
+ }
+ for ( float i=_minstep; i<=dbmax; i+=_minstep ) {
+ h = int( -contentsRect().height() * dbtondb( i ) );
+ if ( _dir==Arts::RightToLeft ) w = 1 - w;
+ if ( left ) p->drawLine( w, 0, w, 6 );
+ p->drawText( w - fontrect.width()/2
+ , ( h - (left)*6 - (right)*6 - fontrect.height() )/2 + (left)*6,
+ fontrect.width(), fontrect.height()+2,
+ Qt::AlignRight|Qt::AlignTop, QString::number( i ) );
+ if ( right ) p->drawLine( w, h-6, w, h );
+ }
+ }
+}
+
+REGISTER_IMPLEMENTATION( KTickmarks_impl );
+
+#include "ktickmarks_impl.moc"
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/ktickmarks_impl.h b/arts/gui/kde/ktickmarks_impl.h
new file mode 100644
index 00000000..5974cf0f
--- /dev/null
+++ b/arts/gui/kde/ktickmarks_impl.h
@@ -0,0 +1,76 @@
+/*
+ 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_KLEVELMETER_TICKMARKS_H
+#define ARTS_KLEVELMETER_TICKMARKS_H
+
+#include <qframe.h>
+#include <math.h>
+
+#include "artsgui.h"
+
+#include "kframe_impl.h"
+
+#include <dbvolcalc.h>
+
+class KTickmarks_Widget;
+
+class KTickmarks_impl : virtual public Arts::Tickmarks_skel,
+ virtual public Arts::KFrame_impl
+{
+public:
+ KTickmarks_impl( QFrame* =0 );
+
+ float min();
+ void min( float );
+ float max();
+ void max( float );
+
+ float minstep();
+ void minstep( float );
+ float substep();
+ void substep( float );
+
+ Arts::Direction direction();
+ void direction( Arts::Direction );
+
+ long position();
+ void position( long );
+
+ void constructor( float min, float max, Arts::Direction, long );
+private:
+ KTickmarks_Widget* _tmwidget;
+};
+
+class KTickmarks_Widget : public QFrame, public dB2VolCalc {
+ Q_OBJECT
+private:
+ KTickmarks_impl* _impl;
+public:
+ KTickmarks_Widget( KTickmarks_impl*, QWidget* =0, const char* =0 );
+ void drawContents( QPainter* );
+ long _pos;
+ Arts::Direction _dir;
+
+ float minstep, substep;
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kvbox_impl.cpp b/arts/gui/kde/kvbox_impl.cpp
new file mode 100644
index 00000000..0b737e78
--- /dev/null
+++ b/arts/gui/kde/kvbox_impl.cpp
@@ -0,0 +1,51 @@
+ /*
+
+ Copyright (C) 2000,2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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 "kvbox_impl.h"
+#include <qvbox.h>
+
+using namespace Arts;
+
+KVBox_impl::KVBox_impl( QVBox * widget )
+ : KFrame_impl( widget ? widget : new QVBox )
+ , _spacing( 5 )
+{
+ _qvbox = static_cast<QVBox*>( _qwidget );
+ _qvbox->setSpacing( _spacing );
+ _qvbox->setMargin( 5 );
+}
+
+long KVBox_impl::spacing()
+{
+ return _spacing;
+}
+
+void KVBox_impl::spacing( long s )
+{
+ _spacing = s;
+ _qvbox->setSpacing( s );
+}
+
+REGISTER_IMPLEMENTATION(KVBox_impl);
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kvbox_impl.h b/arts/gui/kde/kvbox_impl.h
new file mode 100644
index 00000000..9358d90e
--- /dev/null
+++ b/arts/gui/kde/kvbox_impl.h
@@ -0,0 +1,48 @@
+ /*
+
+ Copyright (C) 2000,2001 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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 "kframe_impl.h"
+
+class QVBox;
+
+namespace Arts {
+
+class KVBox_impl : virtual public Arts::VBox_skel,
+ public Arts::KFrame_impl
+{
+private:
+ long _spacing;
+
+protected:
+ QVBox * _qvbox;
+
+public:
+ KVBox_impl( QVBox * w = 0 );
+
+ long spacing();
+ void spacing( long );
+};
+
+}
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kvolumefader_impl.cpp b/arts/gui/kde/kvolumefader_impl.cpp
new file mode 100644
index 00000000..f3d09a0b
--- /dev/null
+++ b/arts/gui/kde/kvolumefader_impl.cpp
@@ -0,0 +1,243 @@
+/*
+ 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 "kvolumefader_impl.h"
+
+#include <kdebug.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qfont.h>
+#include <qfontmetrics.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kaction.h>
+#include <kinputdialog.h>
+
+KVolumeFader_impl::KVolumeFader_impl( QFrame* w )
+ : Arts::KFrame_impl( w ? w : new KVolumeFader_Widget( 0 ) )
+ , dB2VolCalc( -36, 6 )
+ , _dir( Arts::BottomToTop )
+ , dbmin_inupdate( false )
+ , dbmax_inupdate( false )
+ , direction_inupdate( false )
+ , ignoreUpdates( 0 )
+{
+ //kdDebug()<<"KVolumeFader_impl::KVolumeFader_impl( QFrame* w="<<w<<" )"<<endl;
+ _vfwidget = static_cast<KVolumeFader_Widget*>( _qwidget );
+ _vfwidget->setImpl( this );
+}
+
+KVolumeFader_impl::~KVolumeFader_impl() {
+}
+
+float KVolumeFader_impl::dbmin() { return dB2VolCalc::dbmin; }
+void KVolumeFader_impl::dbmin( float n ) {
+ if ( n != dB2VolCalc::dbmin && !dbmin_inupdate ) {
+ dbmin_inupdate = true;
+ dB2VolCalc::dbmin = n;
+ dbmin_changed( dbmin() );
+ dbmin_inupdate = false;
+ }
+}
+float KVolumeFader_impl::dbmax() { return dB2VolCalc::dbmax; }
+void KVolumeFader_impl::dbmax( float n ) {
+ if ( n != dB2VolCalc::dbmax && !dbmax_inupdate ) {
+ dbmax_inupdate = true;
+ dB2VolCalc::dbmax = n;
+ dbmax_changed( dbmax() );
+ dbmax_inupdate = false;
+ }
+}
+
+Arts::Direction KVolumeFader_impl::direction() { return _dir; }
+void KVolumeFader_impl::direction( Arts::Direction n ) {
+ if ( n != _dir && !direction_inupdate ) {
+ direction_inupdate = true;
+ _dir = n;
+ _vfwidget->setDirection( _dir );
+// direction_changed( direction() );
+ direction_inupdate = false;
+ }
+}
+
+float KVolumeFader_impl::volume() { return _volume; }
+void KVolumeFader_impl::volume( float n ) {
+ //kdDebug() << k_funcinfo << n << " ignore: " << ignoreUpdates << endl;
+ if ( ignoreUpdates > 0 ) {
+ --ignoreUpdates;
+ return;
+ }
+ _volume = n;
+ _vfwidget->setValue( amptondb( _volume ) );
+}
+
+float KVolumeFader_impl::dbvolume() { return amptodb( _volume ); }
+void KVolumeFader_impl::dbvolume( float n ) {
+ //kdDebug() << k_funcinfo << n << endl;
+ normalizedvolume( dbtondb( n ) );
+}
+
+void KVolumeFader_impl::normalizedvolume( float n ) {
+ if ( ( ndbtodb( n ) > dbmin() ) && ( ndbtodb( n ) < dbmax() ) ) {
+ float amp = ndbtoamp( n );
+ if ( amp != _volume ) {
+ ++ignoreUpdates;
+ //kdDebug() << k_funcinfo << ignoreUpdates << endl;
+ _volume = amp;
+ _vfwidget->setValue( n );
+ volume_changed( _volume );
+ }
+ }
+}
+
+void KVolumeFader_impl::constructor( float dbmin, float dbmax, Arts::Direction dir ) {
+ this->dbmin( dbmin ); this->dbmax( dbmax ); direction( dir );
+}
+
+
+
+KVolumeFader_Widget::KVolumeFader_Widget( QWidget* p, const char* n )
+ : QFrame( p,n )
+ , _impl( 0 )
+ , _inupdate( false )
+ , _value( -1 )
+ , _dir( Arts::BottomToTop )
+ , _menu( new KPopupMenu( this ) )
+ , _aExactValue( new KAction( i18n( "Set Exact Value..." ), KShortcut(), this, SLOT( exactValue() ), this ) )
+{
+ //kdDebug() << k_funcinfo << endl;
+ setMinimumSize( 10,10 );
+ _aExactValue->plug( _menu );
+}
+
+void KVolumeFader_Widget::setImpl( KVolumeFader_impl* n ) { _impl = n; update(); }
+
+KVolumeFader_Widget::~KVolumeFader_Widget() {
+ //kdDebug() << k_funcinfo << endl;
+}
+
+void KVolumeFader_Widget::setDirection( Arts::Direction n ) { _dir = n; update(); }
+
+void KVolumeFader_Widget::setValue( float n ) {
+ //kdDebug() << k_funcinfo << n << endl;
+ if ( n != _value ) {
+ _value = n;
+ update();
+ }
+}
+
+QColor KVolumeFader_Widget::interpolate( QColor low, QColor high, float percent ) {
+ if ( percent<=0 ) return low; else
+ if ( percent>=1 ) return high; else
+ return QColor(
+ int( low.red() + ( high.red()-low.red() ) * percent ),
+ int( low.green() + ( high.green()-low.green() ) * percent ),
+ int( low.blue() + ( high.blue()-low.blue() ) * percent ) );
+}
+
+void KVolumeFader_Widget::drawContents( QPainter* p ){
+ if ( _dir==Arts::BottomToTop || _dir==Arts::BottomToTop ) {
+ float h;
+ if ( _dir==Arts::BottomToTop ) h = contentsRect().height() * ( 1 - _value );
+ else h = contentsRect().height() * _value;
+ for ( int i=int( h ); i<contentsRect().height(); i++ ) {
+ p->setPen( interpolate( colorGroup().light(), colorGroup().highlight(), float( i )/contentsRect().height() ) );
+ p->drawLine( contentsRect().left(), this->frameWidth() + i, contentsRect().right(), this->frameWidth() + i );
+ }
+ p->setPen( colorGroup().dark() );
+ p->drawLine( contentsRect().left(), this->frameWidth() + int( h ), contentsRect().right(), this->frameWidth() + int( h ) );
+ } else {
+ float w;
+ p->translate( this->width(),0 );
+ if ( _dir==Arts::LeftToRight ) w = - contentsRect().width() * ( 1 - _value );
+ else w = - contentsRect().width() * _value;
+ for ( int i=int( w ); i>=-contentsRect().width(); i-- ) {
+ p->setPen( interpolate( colorGroup().light(), colorGroup().highlight(), float( -i )/contentsRect().width() ) );
+ p->drawLine( this->frameWidth() + i, contentsRect().top(), this->frameWidth() + i, contentsRect().bottom() );
+ }
+ p->setPen( colorGroup().dark() );
+ p->drawLine( this->frameWidth() + int( w ), contentsRect().top(), this->frameWidth() + int( w ), contentsRect().bottom() );
+ }
+}
+
+void KVolumeFader_Widget::mousePressEvent( QMouseEvent* ){
+ //kdDebug() << k_funcinfo << endl;
+}
+
+void KVolumeFader_Widget::mouseReleaseEvent( QMouseEvent* qme ){
+ bool setValue = false;
+ if ( KGlobalSettings::mouseSettings().handed == 0 && qme->button() == Qt::LeftButton ) setValue=true;
+ if ( KGlobalSettings::mouseSettings().handed == 1 && qme->button() == Qt::RightButton ) setValue=true;
+ if ( setValue )
+ {
+ switch ( _dir ) {
+ default:
+ case Arts::BottomToTop:
+ if ( _impl ) _impl->normalizedvolume( 1 - float( qme->y() ) / contentsRect().height() );
+ break;
+ case Arts::TopToBottom:
+ if ( _impl ) _impl->normalizedvolume( float( qme->y() ) / contentsRect().height() );
+ break;
+ case Arts::LeftToRight:
+ if ( _impl ) _impl->normalizedvolume( float( qme->x() ) / contentsRect().width() );
+ break;
+ case Arts::RightToLeft:
+ if ( _impl ) _impl->normalizedvolume( 1 - float( qme->x() ) / contentsRect().width() );
+ break;
+ }
+ } else _menu->exec( qme->globalPos() );
+}
+
+void KVolumeFader_Widget::mouseMoveEvent( QMouseEvent* qme ){
+ switch ( _dir ) {
+ default:
+ case Arts::BottomToTop:
+ if ( _impl ) _impl->normalizedvolume( 1 - float( qme->y() ) / contentsRect().height() );
+ break;
+ case Arts::TopToBottom:
+ if ( _impl ) _impl->normalizedvolume( float( qme->y() ) / contentsRect().height() );
+ break;
+ case Arts::LeftToRight:
+ if ( _impl ) _impl->normalizedvolume( float( qme->x() ) / contentsRect().width() );
+ break;
+ case Arts::RightToLeft:
+ if ( _impl ) _impl->normalizedvolume( 1 - float( qme->x() ) / contentsRect().width() );
+ break;
+ }
+}
+
+void KVolumeFader_Widget::wheelEvent( QWheelEvent* qwe ){
+ //kdDebug() << k_funcinfo << endl;
+ if ( qwe->delta() < 0 ) { if ( _impl ) _impl->normalizedvolume( _impl->dbtondb( _impl->dbvolume() - 1 ) ); }
+ if ( qwe->delta() > 0 ) { if ( _impl ) _impl->normalizedvolume( _impl->dbtondb( _impl->dbvolume() + 1 ) ); }
+}
+
+void KVolumeFader_Widget::exactValue() {
+ //kdDebug() << k_funcinfo << endl;
+ bool ok=false;
+ double n = KInputDialog::getDouble( i18n( "Set Exact Volume Value" ), i18n( "Exact volume (dB):" ), _impl->dbvolume(), _impl->dbmin(), _impl->dbmax(), 1, &ok, this );
+ if ( ok ) _impl->dbvolume( n );
+}
+
+REGISTER_IMPLEMENTATION( KVolumeFader_impl );
+
+#include "kvolumefader_impl.moc"
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kvolumefader_impl.h b/arts/gui/kde/kvolumefader_impl.h
new file mode 100644
index 00000000..31ac438b
--- /dev/null
+++ b/arts/gui/kde/kvolumefader_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_KVOLUMEFADER_TICKMARKS_H
+#define ARTS_KVOLUMEFADER_TICKMARKS_H
+
+#include <qframe.h>
+#include <math.h>
+
+#include "artsgui.h"
+
+#include "kframe_impl.h"
+
+#include <dbvolcalc.h>
+
+class KVolumeFader_Widget;
+
+class KVolumeFader_impl : virtual public Arts::VolumeFader_skel,
+ virtual public Arts::KFrame_impl,
+ public dB2VolCalc
+{
+public:
+ KVolumeFader_impl( QFrame* =0 );
+ ~KVolumeFader_impl();
+
+ float dbmin();
+ void dbmin( float );
+ float dbmax();
+ void dbmax( float );
+
+ Arts::Direction direction();
+ void direction( Arts::Direction );
+
+ float volume();
+ void volume( float );
+ float dbvolume();
+ void dbvolume( float );
+
+ void normalizedvolume( float );
+
+ void constructor( float min, float max, Arts::Direction dir );
+private:
+ KVolumeFader_Widget* _vfwidget;
+ Arts::Direction _dir;
+ bool dbmin_inupdate, dbmax_inupdate, direction_inupdate;
+ float _min, _max, _volume;
+ int ignoreUpdates;
+};
+
+class KPopupMenu;
+class KAction;
+
+class KVolumeFader_Widget : public QFrame {
+ Q_OBJECT
+private:
+ KVolumeFader_impl* _impl;
+ bool _inupdate;
+ float _value;
+ Arts::Direction _dir;
+ KPopupMenu *_menu;
+ KAction *_aExactValue;
+ QColor interpolate( QColor, QColor, float );
+public:
+ KVolumeFader_Widget( QWidget* =0, const char* =0 );
+ ~KVolumeFader_Widget();
+ void setImpl( KVolumeFader_impl* );
+ void setValue( float );
+ void setDirection( Arts::Direction );
+protected:
+ void drawContents( QPainter* );
+ void mousePressEvent( QMouseEvent* );
+ void mouseReleaseEvent( QMouseEvent* );
+ void mouseMoveEvent( QMouseEvent* );
+ void wheelEvent( QWheelEvent* );
+private slots:
+ void exactValue();
+};
+
+#endif
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kwidget_impl.cpp b/arts/gui/kde/kwidget_impl.cpp
new file mode 100644
index 00000000..261cf30b
--- /dev/null
+++ b/arts/gui/kde/kwidget_impl.cpp
@@ -0,0 +1,181 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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 "kwidget_impl.h"
+#include "kwidgetrepo.h"
+#include "debug.h"
+#include <stdio.h>
+
+using namespace Arts;
+
+KWidget_impl::KWidget_impl( QWidget * widget )
+ : _qwidget( widget ? widget : new QWidget )
+{
+ _widgetID = KWidgetRepo::the()->add( this, _qwidget );
+
+ /*
+ * KWidgetGuard will protect us against deleting the widget if Qt already
+ * has done so (for instance if our widget was inside a panel, and
+ * the panel got deleted, our widget will be gone, too)
+ */
+ _guard = new KWidgetGuard(this);
+ QObject::connect(_qwidget, SIGNAL(destroyed()),
+ _guard, SLOT(widgetDestroyed()));
+}
+
+KWidget_impl::~KWidget_impl()
+{
+ if(_qwidget)
+ {
+ delete _qwidget;
+ arts_assert(_qwidget == 0); // should be true due to KWidgetGuard
+ }
+ delete _guard;
+}
+
+void KWidget_impl::widgetDestroyed()
+{
+ KWidgetRepo::the()->remove(_widgetID);
+ _widgetID = 0;
+ _qwidget = 0;
+}
+
+long KWidget_impl::widgetID()
+{
+ return _widgetID;
+}
+
+Widget KWidget_impl::parent()
+{
+ return KWidgetRepo::the()->lookupWidget(_parentID);
+}
+
+void KWidget_impl::parent(Arts::Widget newParent)
+{
+ if(!newParent.isNull())
+ {
+ _parentID = newParent.widgetID();
+
+ QWidget *qparent;
+ qparent = KWidgetRepo::the()->lookupQWidget(newParent.widgetID());
+ if( qparent != 0 )
+ {
+ QPoint pos(x(),y());
+ bool showIt = visible();
+ _qwidget->reparent(qparent, pos, showIt);
+ }
+ }
+ else
+ {
+ _parentID = 0;
+ }
+}
+
+long KWidget_impl::x()
+{
+ return _qwidget->x();
+}
+
+void KWidget_impl::x(long newX)
+{
+ _qwidget->move(newX,y());
+}
+
+long KWidget_impl::y()
+{
+ return _qwidget->y();
+}
+
+void KWidget_impl::y(long newY)
+{
+ _qwidget->move(x(),newY);
+}
+
+long KWidget_impl::width()
+{
+ return _qwidget->width();
+}
+
+void KWidget_impl::width(long newWidth)
+{
+ _qwidget->resize(newWidth,height());
+}
+
+long KWidget_impl::height()
+{
+ return _qwidget->height();
+}
+
+void KWidget_impl::height(long newHeight)
+{
+ _qwidget->resize(width(),newHeight);
+}
+
+bool KWidget_impl::visible()
+{
+ return _qwidget->isVisible();
+}
+
+void KWidget_impl::visible(bool newVisible)
+{
+ if(newVisible) show(); else hide();
+}
+
+SizePolicy KWidget_impl::hSizePolicy()
+{
+ return ( SizePolicy )_qwidget->sizePolicy().horData();
+}
+
+void KWidget_impl::hSizePolicy( SizePolicy p )
+{
+ QSizePolicy sp = _qwidget->sizePolicy();
+ sp.setHorData( ( QSizePolicy::SizeType )p );
+ _qwidget->setSizePolicy( sp );
+}
+
+SizePolicy KWidget_impl::vSizePolicy()
+{
+ return ( SizePolicy )_qwidget->sizePolicy().verData();
+}
+
+void KWidget_impl::vSizePolicy( SizePolicy p )
+{
+ QSizePolicy sp = _qwidget->sizePolicy();
+ sp.setVerData( ( QSizePolicy::SizeType )p );
+ _qwidget->setSizePolicy( sp );
+}
+
+void KWidget_impl::show()
+{
+ _qwidget->show();
+}
+
+void KWidget_impl::hide()
+{
+ _qwidget->hide();
+}
+
+REGISTER_IMPLEMENTATION(KWidget_impl);
+#include "kwidget_impl.moc"
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kwidget_impl.h b/arts/gui/kde/kwidget_impl.h
new file mode 100644
index 00000000..b94f1a8d
--- /dev/null
+++ b/arts/gui/kde/kwidget_impl.h
@@ -0,0 +1,88 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+ 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 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.
+
+ */
+
+#ifndef ARTS_GUI_KWIDGET_IMPL_H
+#define ARTS_GUI_KWIDGET_IMPL_H
+#include "artsgui.h"
+#include <qwidget.h>
+#include <kwidgetrepo.h>
+#include <kdelibs_export.h>
+
+namespace Arts {
+
+class KWidgetGuard;
+class KDE_EXPORT KWidget_impl : virtual public Arts::Widget_skel {
+protected:
+ QWidget * _qwidget;
+ KWidgetGuard * _guard;
+ long _parentID;
+ long _widgetID;
+public:
+ KWidget_impl( QWidget * w = 0 );
+
+ ~KWidget_impl();
+
+ long widgetID();
+ Widget parent();
+ void parent(Arts::Widget);
+ long x();
+ void x(long newX);
+ long y();
+ void y(long newY);
+ long width();
+ void width(long newWidth);
+ long height();
+ void height(long newHeight);
+
+ bool visible();
+ void visible(bool newVisible);
+
+ SizePolicy hSizePolicy();
+ void hSizePolicy( SizePolicy );
+ SizePolicy vSizePolicy();
+ void vSizePolicy( SizePolicy );
+
+ void show();
+ void hide();
+
+ void widgetDestroyed();
+};
+
+class KWidgetGuard : public QObject {
+ Q_OBJECT
+protected:
+ KWidget_impl *impl;
+
+public:
+ KWidgetGuard(KWidget_impl *impl) : impl(impl) { }
+
+public slots:
+ void widgetDestroyed() {
+ impl->widgetDestroyed();
+ }
+};
+
+}
+#endif /* ARTS_GUI_KWIDGET_IMPL_H */
+
+// vim: sw=4 ts=4
diff --git a/arts/gui/kde/kwidgetrepo.cpp b/arts/gui/kde/kwidgetrepo.cpp
new file mode 100644
index 00000000..43dd122d
--- /dev/null
+++ b/arts/gui/kde/kwidgetrepo.cpp
@@ -0,0 +1,89 @@
+ /*
+
+ 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 "kwidgetrepo.h"
+#include "kwidget_impl.h"
+#include <startupmanager.h>
+
+using namespace Arts;
+
+class KWidgetRepoShutdown : public StartupClass {
+public:
+ void startup() {};
+ void shutdown()
+ {
+ KWidgetRepo::shutdown();
+ }
+};
+
+KWidgetRepo *KWidgetRepo::instance = 0;
+
+KWidgetRepo *KWidgetRepo::the()
+{
+ if(!instance)
+ instance = new KWidgetRepo();
+ return instance;
+}
+
+void KWidgetRepo::shutdown()
+{
+ if(instance)
+ {
+ delete instance;
+ instance = 0;
+ }
+}
+
+KWidgetRepo::KWidgetRepo()
+ : nextID(1)
+{
+}
+
+KWidgetRepo::~KWidgetRepo()
+{
+}
+
+
+long KWidgetRepo::add(KWidget_impl *widget, QWidget *qwidget)
+{
+ long ID = nextID++;
+ widgets[ID] = widget;
+ qwidgets[ID] = qwidget;
+ return ID;
+}
+
+QWidget *KWidgetRepo::lookupQWidget(long ID)
+{
+ return qwidgets[ID];
+}
+
+Widget KWidgetRepo::lookupWidget(long ID)
+{
+ if(qwidgets[ID]) /* check existence */
+ return Arts::Widget::_from_base(widgets[ID]->_copy());
+ return Arts::Widget::null();
+}
+
+void KWidgetRepo::remove(long ID)
+{
+ widgets.erase(ID);
+}
diff --git a/arts/gui/kde/kwidgetrepo.h b/arts/gui/kde/kwidgetrepo.h
new file mode 100644
index 00000000..e60cc011
--- /dev/null
+++ b/arts/gui/kde/kwidgetrepo.h
@@ -0,0 +1,56 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef KWIDGETREPO_H
+#define KWIDGETREPO_H
+
+#include <map>
+#include <qwidget.h>
+#include <weakreference.h>
+#include "artsgui.h"
+
+namespace Arts {
+ class KWidget_impl;
+}
+
+class KWidgetRepo {
+protected:
+ long nextID;
+ std::map<long, QWidget *> qwidgets;
+ std::map<long, Arts::KWidget_impl *> widgets;
+ static KWidgetRepo *instance;
+
+ KWidgetRepo();
+ ~KWidgetRepo();
+
+public:
+
+ long add(Arts::KWidget_impl *widget, QWidget *qwidget);
+ Arts::Widget lookupWidget(long ID);
+ QWidget *lookupQWidget(long ID);
+ void remove(long ID);
+
+ static KWidgetRepo *the();
+ static void shutdown();
+};
+
+#endif /* KWIDGETREPO_H */
diff --git a/arts/gui/kde/mcopclass/Button.mcopclass b/arts/gui/kde/mcopclass/Button.mcopclass
new file mode 100644
index 00000000..d5e06c30
--- /dev/null
+++ b/arts/gui/kde/mcopclass/Button.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::Button,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/Fader.mcopclass b/arts/gui/kde/mcopclass/Fader.mcopclass
new file mode 100644
index 00000000..4071180d
--- /dev/null
+++ b/arts/gui/kde/mcopclass/Fader.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::Fader,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/Graph.mcopclass b/arts/gui/kde/mcopclass/Graph.mcopclass
new file mode 100644
index 00000000..f1d98d3a
--- /dev/null
+++ b/arts/gui/kde/mcopclass/Graph.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::Graph,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/GraphLine.mcopclass b/arts/gui/kde/mcopclass/GraphLine.mcopclass
new file mode 100644
index 00000000..57b48f2c
--- /dev/null
+++ b/arts/gui/kde/mcopclass/GraphLine.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::GraphLine,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/HBox.mcopclass b/arts/gui/kde/mcopclass/HBox.mcopclass
new file mode 100644
index 00000000..fce0f113
--- /dev/null
+++ b/arts/gui/kde/mcopclass/HBox.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::HBox,Arts::Frame,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/Label.mcopclass b/arts/gui/kde/mcopclass/Label.mcopclass
new file mode 100644
index 00000000..2bad3990
--- /dev/null
+++ b/arts/gui/kde/mcopclass/Label.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::Label,Arts::Frame,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/LayoutBox.mcopclass b/arts/gui/kde/mcopclass/LayoutBox.mcopclass
new file mode 100644
index 00000000..48292c85
--- /dev/null
+++ b/arts/gui/kde/mcopclass/LayoutBox.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::LayoutBox,Arts::Frame,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/LevelMeter.mcopclass b/arts/gui/kde/mcopclass/LevelMeter.mcopclass
new file mode 100644
index 00000000..77f804b9
--- /dev/null
+++ b/arts/gui/kde/mcopclass/LevelMeter.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::LevelMeter,Arts::Frame,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/LineEdit.mcopclass b/arts/gui/kde/mcopclass/LineEdit.mcopclass
new file mode 100644
index 00000000..69b68703
--- /dev/null
+++ b/arts/gui/kde/mcopclass/LineEdit.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::LineEdit,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/Makefile.am b/arts/gui/kde/mcopclass/Makefile.am
new file mode 100644
index 00000000..fac44b22
--- /dev/null
+++ b/arts/gui/kde/mcopclass/Makefile.am
@@ -0,0 +1,5 @@
+mcopclassdir = $(libdir)/mcop/Arts
+mcopclass_DATA = Widget.mcopclass Button.mcopclass Poti.mcopclass \
+ LineEdit.mcopclass HBox.mcopclass VBox.mcopclass SpinBox.mcopclass \
+ Fader.mcopclass GraphLine.mcopclass LayoutBox.mcopclass \
+ PopupBox.mcopclass LevelMeter.mcopclass Label.mcopclass
diff --git a/arts/gui/kde/mcopclass/PopupBox.mcopclass b/arts/gui/kde/mcopclass/PopupBox.mcopclass
new file mode 100644
index 00000000..5ac282d1
--- /dev/null
+++ b/arts/gui/kde/mcopclass/PopupBox.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::PopupBox,Arts::Frame,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/Poti.mcopclass b/arts/gui/kde/mcopclass/Poti.mcopclass
new file mode 100644
index 00000000..cae9a5e9
--- /dev/null
+++ b/arts/gui/kde/mcopclass/Poti.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::Poti,Arts::Frame,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/SpinBox.mcopclass b/arts/gui/kde/mcopclass/SpinBox.mcopclass
new file mode 100644
index 00000000..68cfc5eb
--- /dev/null
+++ b/arts/gui/kde/mcopclass/SpinBox.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::SpinBox,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/VBox.mcopclass b/arts/gui/kde/mcopclass/VBox.mcopclass
new file mode 100644
index 00000000..b32c302e
--- /dev/null
+++ b/arts/gui/kde/mcopclass/VBox.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::VBox,Arts::Frame,Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/gui/kde/mcopclass/Widget.mcopclass b/arts/gui/kde/mcopclass/Widget.mcopclass
new file mode 100644
index 00000000..54a6e91f
--- /dev/null
+++ b/arts/gui/kde/mcopclass/Widget.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=Arts::Widget,Arts::Object
+Language=C++
+Library=libartsgui_kde.la
+Requires=kdegui
diff --git a/arts/midi/Makefile.am b/arts/midi/Makefile.am
new file mode 100644
index 00000000..b5719649
--- /dev/null
+++ b/arts/midi/Makefile.am
@@ -0,0 +1,53 @@
+####### Various modules for artsmodules
+
+SUBDIRS = mcopclass
+INCLUDES= -I$(top_builddir)/arts/runtime -I$(srcdir)/freeverb -I$(arts_includes) $(all_includes)
+
+lib_LTLIBRARIES = libartsmidi_idl.la libartsmidi.la
+
+bin_PROGRAMS = midisend
+noinst_PROGRAMS = midisynctest
+
+midisend_SOURCES = midisend.cc midimsg.c
+midisend_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIBPTHREAD)
+midisend_LDADD = libartsmidi_idl.la
+midisend_COMPILE_FIRST = artsmidi.h
+
+midisynctest_SOURCES = midisynctest.cc
+midisynctest_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIBPTHREAD)
+midisynctest_LDADD = libartsmidi.la -lsoundserver_idl
+midisynctest_COMPILE_FIRST = artsmidi.h
+
+libartsmidi_idl_la_SOURCES = artsmidi.cc
+libartsmidi_idl_la_LIBADD = -lmcop -lartsflow
+libartsmidi_idl_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) \
+ -no-undefined
+
+libartsmidi_la_SOURCES = midimanager_impl.cc midiclient_impl.cc \
+ miditest_impl.cc midimanagerport_impl.cc rawmidiport_impl.cc \
+ systemmiditimer_impl.cc audiomiditimer_impl.cc miditimercommon.cc \
+ audiosync_impl.cc audiotimer.cc alsamidigateway_impl.cc \
+ alsamidiport_impl.cc midisyncgroup_impl.cc timestampmath.cc
+libartsmidi_la_COMPILE_FIRST = artsmidi.h
+
+libartsmidi_la_LIBADD = libartsmidi_idl.la -lartsflow $(ARTS_LIBASOUND)
+libartsmidi_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) \
+ -no-undefined
+
+artsmidi.mcopclass: artsmidi.h
+artsmidi.mcoptype: artsmidi.h
+artsmidi.cc artsmidi.h: $(srcdir)/artsmidi.idl $(MCOPIDL)
+ $(MCOPIDL) -t -I$(arts_includes) $(srcdir)/artsmidi.idl
+
+DISTCLEANFILES = artsmidi.cc artsmidi.h \
+ artsmidi.mcoptype artsmidi.mcopclass
+
+####### install idl files
+
+artsincludedir = $(includedir)/arts
+artsinclude_HEADERS = artsmidi.h artsmidi.idl
+
+mcoptypedir = $(libdir)/mcop
+mcoptype_DATA = artsmidi.mcoptype artsmidi.mcopclass
+
+artsmidi.lo: artsmidi.h
diff --git a/arts/midi/README.midi b/arts/midi/README.midi
new file mode 100644
index 00000000..e341ca01
--- /dev/null
+++ b/arts/midi/README.midi
@@ -0,0 +1,261 @@
+Midi, Audio and Synchronization:
+================================
+
+1. Introduction
+2. The midi manager
+3. Midi synchronization
+4. Audio timestamping and synchronization
+5. Example code
+
+
+ 1. Introduction
+ ---------------
+
+Since aRts-1.0 (as shipped with KDE3.0), aRts provides a lot more
+infrastructure to deal with midi, audio, and their synchronization. The main
+goal is to provide a unified interface between sequencers (or other programs
+that require notes or audio tracks to be played at certain given time stamps)
+and underlying software/hardware that can play notes/audio tracks.
+
+Currently, there exist five distinct destinations that aRts supports, which
+can all be used at the same time or individually, that is:
+
+ * aRts synthetic midi instruments
+ * ALSA-0.5
+ * ALSA-0.9
+ * OSS
+ * other aRts modules (including but not limited to the playback/recording
+ of audio tracks)
+
+ 2. The midi manager
+ -------------------
+
+The midi manager is the basic component that connects between applications
+that supply/record midi data, and devices that process midi data. Devices
+might be both, virtual (as in software synthesis) or real (as in hardware
+devices).
+
+From the view of the midi manager, all event streams correspond to one midi
+client. So, a midi client might be an application (such as a sequencer) that
+provides events, or an ALSA hardware device that consumes events. If there
+are multiple event streams, they correspond to multiple clients. That is,
+if an application wishes to play three different midi tracks, one over ALSA,
+and two over two different synthetic instruments, it needs to register itself
+three times, with three different clients.
+
+The midi managers job is to connect midi clients (as in event streams). It
+maintains a list of connections that the user can modify with an application
+like artscontrol. Applications could also, if they wish so, modify this
+connection list.
+
+As a use case, we'll consider the following: you want to write a sequencer
+application that plays back two different tracks to two different devices.
+You want the user to be able to select these devices in a drop down box for
+each track.
+
+1) getting a list of choices:
+
+First, you will want to obtain a list of choices which the user could possibly
+connect your tracks to. You do so by reading the
+
+interface MidiManager { // SINGLETON: Arts_MidiManager
+ /**
+ * a list of clients
+ */
+ readonly attribute sequence<MidiClientInfo> clients;
+
+ //...
+};
+
+attribute. The three fields of each client that are interesting for you are
+
+struct MidiClientInfo {
+ long ID;
+
+ //...
+
+ MidiClientDirection direction;
+ MidiClientType type;
+ string title;
+};
+
+You would list those devices in the dropdown box that are of the appropriate
+direction, which is mcdRecord, as you would want a client that receives midi
+events (this might be confusing, but you look from the view of the client).
+
+Then, there is the type field, which tells you whether the client is a device-
+like thing (like a synthetic instrument), or another application (like another
+application currently recording a track). While it might not be an impossible
+setup that you send events between two applications, usually users will choose
+such clients that have mctDestination as type.
+
+Finally, you can list the titles in a drop down box, and keep the ID for making
+a connection later.
+
+2) registering clients:
+
+You will need to register one client for each track. Use
+
+ /**
+ * add a client
+ *
+ * this creates a new MidiManagerClient
+ */
+ MidiClient addClient(MidiClientDirection direction, MidiClientType type,
+ string title, string autoRestoreID);
+
+to do so.
+
+3) connecting:
+
+As you probably don't want your sequencer user to use artscontrol to setup
+connections between your tracks and the devices, you will need to connect
+your clients to the hardware devices for playing something.
+
+You can connect clients to their appropriate destinations using
+
+ /**
+ * connect two clients
+ */
+ void connect(long clientID, long destinationID);
+
+and
+
+ /**
+ * disconnect two clients
+ */
+ void disconnect(long clientID, long destinationID);
+
+Keep in mind that a client might be connected to more than one destination
+at the same time, so that you will need to disconnect the old destination
+before connecting the new one.
+
+4) playing events:
+
+You can now play events to the tracks, using each client's
+
+ MidiPort addOutputPort();
+
+function for getting a port where you can send events to. However, you will
+also need to ensure that the events will get synchronized as soon as you are
+playing back events to different devices. Read the next section for details
+on this.
+
+ 3. Midi synchronization
+ -----------------------
+
+As soon as you are writing a real sequencer, you might want to output to more
+than one midi device at a time. For instance, you might want to let some of
+your midi events be played by aRts synthesis, while others should be sent
+over the external midi port.
+
+To support this setup, a new interface called MidiSyncGroup has been added. To
+output midi events synchronized over more than one port, you proceed as follows:
+
+a) you obtain a reference to the midi manager object
+
+ MidiManager midiManager = DynamicCast(Reference("global:Arts_MidiManager"));
+ if(midiManager.isNull()) arts_fatal("midimanager is null");
+
+b) you create a midi synchronization group which will ensure that the
+ timestamps of your midi events will be synchronized
+
+ MidiSyncGroup syncGroup = midiManager.addSyncGroup();
+
+c) you add a client to the midi manager for each port you want to output
+ midi data over
+
+ MidiClient client = midiManager.addClient(mcdPlay, mctApplication, "midisynctest", "midisynctest");
+ MidiClient client2 = midiManager.addClient(mcdPlay, mctApplication, "midisynctest2", "midisynctest2");
+
+d) you insert the clients in the synchronization group
+
+ syncGroup.addClient(client);
+ syncGroup.addClient(client2);
+
+e) you create ports for each client as usual
+
+ MidiPort port = client.addOutputPort();
+ MidiPort port2 = client2.addOutputPort();
+
+f) at this point, you will need to ensure that the midi clients you created
+ are connected, you can either leave the user with artscontrol for doing
+ this, or use the clients and connect methods of the midiManager object
+ yourself (see use case discussed in previous section)
+
+g) you output events over the ports as usual
+
+ /* where t is a suitable TimeStamp */
+ MidiEvent e = MidiEvent(t,MidiCommand(mcsNoteOn|0, notes[np], 100));
+ port.processEvent(e);
+ port2.processEvent(e);
+
+ 4. Audio timestamping and synchronization
+ -----------------------------------------
+
+Audio in aRts is usually handled as structures consisting of small modules
+that do something. While this model allows you to describe anything you want
+to, from playing a sample to playing a synthetic sequence of notes with a
+synthetic instruments, it doesn't give you any notion of time. More so, if
+you build a large graph of objects, you might need quite some time for this,
+and you will want to have them all started at the same time.
+
+To solve this issue, an AudioSync interface has been introduced, that allows
+you to start() and stop() either synchronized at a specific point in time.
+
+Suppose you have two synthesis modules which together play back a sample.
+What can you do to start them at the same time?
+
+ Synth_PLAY_WAV wav = //... create on server
+ Synth_AMAN_PLAY sap //... create on server
+ AudioSync audioSync = //... create on server
+
+ wav.filename("/opt/kde3/share/sounds/pop.wav");
+ sap.title("midisynctest2");
+ sap.autoRestoreID("midisynctest2");
+ connect(wav,sap);
+
+ // this queues back start() to be called atomically later
+ audioSync.queueStart(wav);
+ audioSync.queueStart(sap);
+
+ // this line is a synchronized version of
+ // wav.start();
+ // sap.start();
+ audioSync.execute();
+
+You could also play them back at a specific time in the future and query the
+current time using the time and executeAt methods:
+
+interface AudioSync {
+ /**
+ * the current time
+ */
+ readonly attribute TimeStamp time;
+
+ //...
+
+ /**
+ * atomically executes all queued modifications to the flow system
+ * at a given time
+ */
+ void executeAt(TimeStamp timeStamp);
+};
+
+Finally, to get synchronized midi and audio, you can insert the AudioSync
+object into a midi synchronization group, then their timestamps will be
+synchronized to those of the midi channels.
+
+ 5. Example code
+ ---------------
+
+An example that illustrates most things discussed in this document is
+midisynctest.cc, which plays back two synchronized midi streams and samples.
+Note that you might want to change the source code, as it hardcodes the
+location of the .wav file.
+
+
+Questions and comments are welcome.
+
+Stefan Westerfeld
+stefan@space.twc.de
diff --git a/arts/midi/alsamidigateway_impl.cc b/arts/midi/alsamidigateway_impl.cc
new file mode 100644
index 00000000..91a0f118
--- /dev/null
+++ b/arts/midi/alsamidigateway_impl.cc
@@ -0,0 +1,243 @@
+ /*
+
+ 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 "artsmidi.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/**
+ * compile real version if we have ALSA support, dummy version otherwise
+ */
+#if defined(HAVE_ARTS_LIBASOUND2) || defined(HAVE_ARTS_LIBASOUND)
+
+#ifdef HAVE_ALSA_ASOUNDLIB_H
+#include <alsa/asoundlib.h>
+#elif defined(HAVE_SYS_ASOUNDLIB_H)
+#include <sys/asoundlib.h>
+#endif
+
+#include "alsamidiport_impl.h"
+#include <arts/debug.h>
+#include <stdio.h>
+
+using namespace Arts;
+using namespace std;
+
+class AlsaMidiGateway_impl : virtual public AlsaMidiGateway_skel {
+protected:
+ snd_seq_t *seq;
+
+ struct PortEntry {
+ int alsaClient, alsaPort;
+ bool keep;
+
+ AlsaMidiPort port;
+ MidiClient client;
+ };
+ list<PortEntry> ports;
+
+#ifdef HAVE_ARTS_LIBASOUND2
+/* ALSA-0.9 specific code */
+ int alsaOpen() {
+ return snd_seq_open(&seq, "hw", SND_SEQ_OPEN_DUPLEX, 0);
+ }
+ bool alsaScan(MidiManager midiManager) {
+ snd_seq_client_info_t *cinfo;
+ snd_seq_port_info_t *pinfo;
+
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_client_info_set_client(cinfo, -1);
+
+ while (snd_seq_query_next_client(seq, cinfo) >= 0) {
+ int client = snd_seq_client_info_get_client(cinfo);
+
+ snd_seq_port_info_alloca(&pinfo);
+ snd_seq_port_info_set_client(pinfo, client);
+
+ snd_seq_port_info_set_port(pinfo, -1);
+ while (snd_seq_query_next_port(seq, pinfo) >= 0) {
+ unsigned int cap;
+
+ cap = (SND_SEQ_PORT_CAP_SUBS_WRITE|SND_SEQ_PORT_CAP_WRITE);
+ if ((snd_seq_port_info_get_capability(pinfo) & cap) == cap) {
+ string name = snd_seq_port_info_get_name(pinfo);
+ int client = snd_seq_port_info_get_client(pinfo);
+ int port = snd_seq_port_info_get_port(pinfo);
+
+ createPort(midiManager, name, client, port);
+ }
+ }
+ }
+
+ return true;
+ }
+#else
+/* ALSA-0.5 specific code */
+ int alsaOpen() {
+ return snd_seq_open(&seq, SND_SEQ_OPEN);
+ }
+
+ bool alsaScan(MidiManager midiManager) {
+ snd_seq_system_info_t sysinfo;
+
+ int err = snd_seq_system_info(seq, &sysinfo);
+ if (err < 0)
+ {
+ arts_warning("snd_seq_systeminfo failed: %s", snd_strerror(err));
+ return false;
+ }
+
+ for(int client = 0; client < sysinfo.clients; client++)
+ {
+ snd_seq_client_info_t cinfo;
+ if (snd_seq_get_any_client_info(seq, client, &cinfo) == 0)
+ {
+ for(int port = 0; port < sysinfo.ports; port++)
+ {
+ snd_seq_port_info_t pinfo;
+ if(snd_seq_get_any_port_info(seq, client, port, &pinfo) == 0)
+ {
+ unsigned int cap;
+ cap = (SND_SEQ_PORT_CAP_SUBS_WRITE|SND_SEQ_PORT_CAP_WRITE);
+
+ if ((pinfo.capability & cap) == cap)
+ createPort(midiManager, pinfo.name, client, port);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+#endif
+
+public:
+ AlsaMidiGateway_impl() : seq(0)
+ {
+ }
+
+ ~AlsaMidiGateway_impl()
+ {
+ if(seq)
+ snd_seq_close(seq);
+ }
+
+ void createPort(MidiManager midiManager, string name, int client, int port)
+ {
+ if(name != "aRts")
+ {
+ char nr[1024];
+
+ sprintf(nr, " (%3d:%-3d)", client, port);
+ name += nr;
+
+ list<PortEntry>::iterator pi = ports.begin();
+ while(pi != ports.end() && (pi->alsaClient != client || pi->alsaPort != port))
+ pi++;
+
+ if(pi != ports.end()) /* we already have this port */
+ pi->keep = true;
+ else /* we need to create it */
+ {
+ PortEntry pe;
+ pe.port = AlsaMidiPort::_from_base(
+ new AlsaMidiPort_impl(seq, client, port));
+
+ if(pe.port.open())
+ {
+ pe.client = midiManager.addClient(mcdRecord,
+ mctDestination,
+ name, name);
+ pe.client.addInputPort(pe.port);
+ pe.alsaClient = client;
+ pe.alsaPort = port;
+ pe.keep = true;
+
+ ports.push_back(pe);
+ }
+ }
+ }
+ }
+
+ bool rescan()
+ {
+ MidiManager midiManager = DynamicCast(Reference("global:Arts_MidiManager"));
+ if(midiManager.isNull())
+ {
+ arts_warning("AlsaMidiGateway: can't find MidiManager");
+ return false;
+ }
+
+ if(!seq)
+ {
+ int err = alsaOpen();
+ if (err < 0)
+ {
+ arts_warning("AlsaMidiGateway: could not open sequencer %s",
+ snd_strerror(err));
+ seq = 0;
+ return false;
+ }
+ }
+
+ list<PortEntry>::iterator pi;
+ for(pi = ports.begin(); pi != ports.end(); pi++)
+ pi->keep = false;
+
+ if(!alsaScan(midiManager))
+ return false;
+
+ /* erase those ports that are no longer needed */
+ pi = ports.begin();
+ while(pi != ports.end())
+ {
+ if(!pi->keep)
+ pi = ports.erase(pi);
+ else
+ pi++;
+ }
+
+ return true;
+ }
+};
+
+#else
+
+using namespace Arts;
+using namespace std;
+
+class AlsaMidiGateway_impl : virtual public AlsaMidiGateway_skel {
+public:
+ bool rescan()
+ {
+ /* dummy version: no ALSA support compiled in */
+ return false;
+ }
+};
+
+#endif
+
+namespace Arts {
+ REGISTER_IMPLEMENTATION(AlsaMidiGateway_impl);
+}
diff --git a/arts/midi/alsamidiport_impl.cc b/arts/midi/alsamidiport_impl.cc
new file mode 100644
index 00000000..e53d7fe7
--- /dev/null
+++ b/arts/midi/alsamidiport_impl.cc
@@ -0,0 +1,232 @@
+ /*
+
+ 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 "alsamidiport_impl.h"
+
+#if defined(HAVE_ARTS_LIBASOUND2) || defined(HAVE_ARTS_LIBASOUND)
+#include <arts/debug.h>
+
+#ifdef HAVE_ARTS_LIBASOUND
+#define snd_seq_queue_status_alloca(x) \
+ *x = (snd_seq_queue_status_t *)alloca(sizeof(snd_seq_queue_status_t))
+#define snd_seq_queue_status_get_tick_time(x) x->tick
+#define snd_seq_queue_status_get_real_time(x) (&(x->time))
+#endif
+
+using namespace std;
+using namespace Arts;
+
+AlsaMidiPort_impl::AlsaMidiPort_impl(snd_seq_t *seq, long client, long port)
+ : _client(client), _port(port), alsaSeq(seq)
+{
+ opened = false;
+}
+
+/* interface MidiPort */
+Arts::TimeStamp AlsaMidiPort_impl::time()
+{
+ snd_seq_queue_status_t *status;
+ snd_seq_queue_status_alloca(&status);
+
+ snd_seq_get_queue_status(alsaSeq, alsaQueue, status);
+ snd_seq_tick_time_t ttime = snd_seq_queue_status_get_tick_time(status);
+ const snd_seq_real_time_t *rtime =
+ snd_seq_queue_status_get_real_time(status);
+
+ return Arts::TimeStamp(rtime->tv_sec, rtime->tv_nsec / 1000);
+}
+
+Arts::TimeStamp AlsaMidiPort_impl::playTime()
+{
+ return time();
+}
+
+void AlsaMidiPort_impl::fillAlsaEvent(snd_seq_event_t *ev,
+ const MidiCommand& command)
+{
+ ev->source = alsaSourceAddr;
+ ev->dest = alsaDestAddr;
+
+ mcopbyte channel = command.status & mcsChannelMask;
+
+ switch(command.status & mcsCommandMask)
+ {
+ case mcsNoteOn:
+ snd_seq_ev_set_noteon(ev, channel, command.data1, command.data2);
+ break;
+ case mcsNoteOff:
+ snd_seq_ev_set_noteoff(ev, channel, command.data1, command.data2);
+ break;
+ case mcsProgram:
+ snd_seq_ev_set_pgmchange(ev, channel, command.data1);
+ break;
+ case mcsParameter:
+ snd_seq_ev_set_controller(ev, channel, command.data1, command.data2);
+ break;
+ default:
+ /* unhandled */
+ return;
+ }
+}
+
+void AlsaMidiPort_impl::sendAlsaEvent(snd_seq_event_t *ev)
+{
+ int ret = snd_seq_event_output(alsaSeq, ev);
+ if (ret < 0) {
+ arts_warning("AlsaMidiPort: error writing note %s\n",
+ snd_strerror(ret));
+ return;
+ }
+ flushAlsa();
+}
+
+void AlsaMidiPort_impl::processCommand(const MidiCommand& command)
+{
+ snd_seq_event_t ev;
+ snd_seq_ev_clear(&ev);
+
+ fillAlsaEvent(&ev, command);
+ sendAlsaEvent(&ev);
+}
+
+void AlsaMidiPort_impl::processEvent(const MidiEvent& event)
+{
+ snd_seq_event_t ev;
+ snd_seq_real_time_t time;
+
+ time.tv_sec = event.time.sec;
+ time.tv_nsec = event.time.usec * 1000;
+
+ snd_seq_ev_clear(&ev);
+ snd_seq_ev_schedule_real(&ev, alsaQueue, 0, &time);
+
+ fillAlsaEvent(&ev, event.command);
+ sendAlsaEvent(&ev);
+}
+
+/* interface AlsaMidiPort */
+void AlsaMidiPort_impl::client(long newClient)
+{
+ if(newClient != _client)
+ {
+ _client = newClient;
+
+ if(opened)
+ {
+ close();
+ open();
+ }
+
+ client_changed(newClient);
+ }
+}
+
+long AlsaMidiPort_impl::client()
+{
+ return _client;
+}
+
+void AlsaMidiPort_impl::port(long newPort)
+{
+ if(newPort != _port)
+ {
+ _port = newPort;
+
+ if(opened)
+ {
+ close();
+ open();
+ }
+
+ port_changed(newPort);
+ }
+}
+
+long AlsaMidiPort_impl::port()
+{
+ return _port;
+}
+
+bool AlsaMidiPort_impl::open()
+{
+ arts_return_val_if_fail(opened == false, false);
+
+ alsaQueue = snd_seq_alloc_queue(alsaSeq);
+ alsaClientId = snd_seq_client_id(alsaSeq);
+
+ alsaPort = snd_seq_create_simple_port(alsaSeq, "aRts",
+ SND_SEQ_PORT_CAP_WRITE |
+ SND_SEQ_PORT_CAP_SUBS_WRITE |
+ SND_SEQ_PORT_CAP_READ,
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC);
+ if (alsaPort < 0) {
+ arts_warning("AlsaMidiPort: can't creating port %s\n",
+ snd_strerror(alsaPort));
+ return false;
+ }
+
+ alsaSourceAddr.client = alsaClientId;
+ alsaSourceAddr.port = alsaPort;
+
+ alsaDestAddr.client = _client;
+ alsaDestAddr.port = _port;
+
+ int ret;
+ ret = snd_seq_connect_to(alsaSeq, alsaPort,
+ alsaDestAddr.client,
+ alsaDestAddr.port);
+ if (ret < 0) {
+ arts_warning("AlsaMidiPort: error connecting port %s\n",
+ snd_strerror(ret));
+ /* FIXME: destroy port here */
+ return false;
+ }
+
+ snd_seq_start_queue(alsaSeq, alsaQueue, 0);
+ flushAlsa();
+
+ opened = true;
+ return true;
+}
+
+void AlsaMidiPort_impl::close()
+{
+ if(!opened)
+ return;
+
+ opened = false;
+}
+
+void AlsaMidiPort_impl::flushAlsa()
+{
+#ifdef HAVE_ARTS_LIBASOUND2
+ snd_seq_drain_output(alsaSeq);
+#else
+ int err;
+ while((err = snd_seq_flush_output(alsaSeq)) > 0)
+ {
+ arts_debug("alsa flush error %d\n",snd_strerror(err));
+ usleep(2000);
+ }
+#endif
+}
+#endif
diff --git a/arts/midi/alsamidiport_impl.h b/arts/midi/alsamidiport_impl.h
new file mode 100644
index 00000000..251f9d94
--- /dev/null
+++ b/arts/midi/alsamidiport_impl.h
@@ -0,0 +1,85 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef ARTS_ALSAMIDIPORT_IMPL_H
+#define ARTS_ALSAMIDIPORT_IMPL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/**
+ * compile real version if we have ALSA support, dummy version otherwise
+ */
+#if defined(HAVE_ARTS_LIBASOUND2) || defined(HAVE_ARTS_LIBASOUND)
+
+#ifdef HAVE_ALSA_ASOUNDLIB_H
+#include <alsa/asoundlib.h>
+#elif defined(HAVE_SYS_ASOUNDLIB_H)
+#include <sys/asoundlib.h>
+#endif
+
+#include "artsmidi.h"
+
+namespace Arts {
+
+class AlsaMidiPort_impl : virtual public AlsaMidiPort_skel {
+protected:
+ long _client, _port;
+ bool opened;
+
+ snd_seq_t *alsaSeq;
+
+ int alsaQueue;
+ int alsaClientId;
+ int alsaPort;
+
+ snd_seq_addr_t alsaSourceAddr;
+ snd_seq_addr_t alsaDestAddr;
+
+ void fillAlsaEvent(snd_seq_event_t *ev, const MidiCommand& command);
+ void sendAlsaEvent(snd_seq_event_t *ev);
+ void flushAlsa();
+
+public:
+ AlsaMidiPort_impl(snd_seq_t *seq, long client, long port);
+ void close();
+
+ /* interface MidiPort */
+ Arts::TimeStamp time();
+ Arts::TimeStamp playTime();
+ void processCommand(const MidiCommand& command);
+ void processEvent(const MidiEvent& event);
+
+ /* interface AlsaMidiPort */
+ void client(long newClient);
+ long client();
+
+ void port(long newPort);
+ long port();
+
+ bool open();
+};
+
+}
+#endif /* HAVE_ARTS_LIBASOUND2 */
+#endif /* ARTS_ALSAMIDIPORT_IMPL_H */
diff --git a/arts/midi/artsmidi.idl b/arts/midi/artsmidi.idl
new file mode 100644
index 00000000..63bf868b
--- /dev/null
+++ b/arts/midi/artsmidi.idl
@@ -0,0 +1,379 @@
+ /*
+
+ 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.
+
+ */
+
+/*
+ * DISCLAIMER: The interfaces in artsmidi.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>
+
+module Arts {
+
+/* This is modelled somewhat after
+ - the AudioManager concept
+ - the aRts-0.3.4.1 MidiPort concept
+ - libkmid
+
+ It adds timing as new feature compared to older implementation, and also
+ tries to do the full set of midi operations.
+
+ It's current state is "experimental", and "binary compatibility not kept".
+ */
+
+/**
+ * an absolute timestamp
+ */
+struct TimeStamp {
+ long sec,usec;
+};
+
+/**
+ * different status of a midi command
+ */
+enum MidiCommandStatus {
+// Masks:
+ mcsCommandMask = 0xf0,
+ mcsChannelMask = 0x0f,
+
+// Commands:
+ mcsNoteOff = 0x80,
+ mcsNoteOn = 0x90,
+ mcsKeyPressure = 0xa0,
+ mcsParameter = 0xb0,
+ mcsProgram = 0xc0,
+ mcsChannelPressure = 0xd0,
+ mcsPitchWheel = 0xe0
+};
+
+/**
+ * the following are to be used once status is (mcsParameter|channel):
+ */
+enum MidiCommandParameter {
+ mcpSustain = 0x40,
+ mcpAllNotesOff = 0x7b
+};
+
+/**
+ * a midi command
+ */
+struct MidiCommand {
+ byte status;
+ byte data1;
+ byte data2;
+};
+
+/**
+ * a midi event
+ */
+
+struct MidiEvent {
+ TimeStamp time;
+ MidiCommand command;
+};
+
+/**
+ * a midi port
+ */
+interface MidiPort {
+ /**
+ * the current absolute time (since the existence of the midi device)
+ */
+ readonly attribute TimeStamp time;
+
+ /**
+ * the current play time
+ *
+ * Some midi devices, for instance synthetic audio devices, have a certain
+ * amount of internal buffering. This causes a time difference between
+ * where events are currently being rendered, which is the timestamp
+ * obtained by "time", and the events that the listener is hearing right
+ * now, which is this timestamp, the "playTime".
+ */
+ readonly attribute TimeStamp playTime;
+
+ /**
+ * processes a midi command
+ */
+ oneway void processCommand(MidiCommand command);
+
+ /**
+ * processes a midi event
+ */
+ oneway void processEvent(MidiEvent event);
+};
+
+enum MidiClientDirection { mcdPlay, mcdRecord };
+enum MidiClientType { mctDestination, mctApplication };
+
+/**
+ * information about a midi client
+ */
+struct MidiClientInfo {
+ long ID;
+ sequence<long> connections;
+
+ MidiClientDirection direction;
+ MidiClientType type;
+ string title, autoRestoreID;
+};
+
+/**
+ * a midi manager client
+ */
+interface MidiClient {
+ readonly attribute MidiClientInfo info;
+
+ /**
+ * you can change the title of your client on the fly - everything else
+ * (besides the actual assignment) is static
+ */
+ attribute string title;
+
+ /**
+ * creates a new port through which the client can receive data from
+ * the midi manager
+ */
+ void addInputPort(MidiPort port);
+
+ /**
+ * creates a new port through which the client can send data to the
+ * midi manager
+ */
+ MidiPort addOutputPort();
+
+ /**
+ * removes a port
+ */
+ void removePort(MidiPort port);
+};
+
+interface AudioSync;
+
+/**
+ * this synchronizes multiple midi clients - it also allows synchronization
+ * with audio events
+ */
+interface MidiSyncGroup {
+ /**
+ * adds a midi client to the synchronization group
+ *
+ * hint: during adding the client, the timestamps related to that
+ * client will jump
+ */
+ void addClient(MidiClient client);
+
+ /**
+ * deletes a midi client from the synchronization group
+ */
+ void removeClient(MidiClient client);
+
+ /**
+ * adds an AudioSync object to the synchronization group
+ *
+ * hint: during adding the AudioSync object, the timestamps related to
+ * that object might jump
+ */
+ void addAudioSync(AudioSync audioSync);
+
+ /**
+ * deletes an AudioSync object from the synchronization group
+ */
+ void removeAudioSync(AudioSync audioSync);
+};
+
+/**
+ * Some general notes to the understanding of the midi manager. The midi
+ * manager has the task to intelligently assign applications to destinations.
+ *
+ * It is important to understand what it actually does to understand the
+ * distinction first, which is expressed through the "MidiClientType" of
+ * each client.
+ *
+ * APPLICATIONS: An application is a user visible application, that produces
+ * or records midi data. It is important for the understanding of an
+ * application, that an application actually *wants* to be supplied with
+ * data, or wants to get its data played. Thus, adding an application to
+ * the midi manager is an implicit request: "go and find a place where to
+ * put the events to (or get the events from)".
+ *
+ * Examples for applications would be games or midi players.
+ *
+ * DESTINATIONS: A destination is a system service that plays or supplies
+ * midi data. The characteristic here is that a destination is something
+ * that is there if you need it.
+ *
+ * Examples for destinations might be might be a hardware device or an
+ * emulation of a hardware device (such as a virtual sampler).
+ *
+ * So the process is as follows:
+ * - destinations register themselves at the midi manager, and provide
+ * system services in that way
+ *
+ * - when the user starts an application (such as a midi player), the midi
+ * manager's task is to assign it to a suitable destination
+ *
+ * - the user can interact with the process by changing the way applications
+ * are assigned to destinations - the midi manager will try to learn
+ * what the user wants, and next time do a better job while assigning
+ *
+ * To actually record or play some data, you need to register a client first,
+ * and after that, you can add Input or Output "MidiPort"s to your client,
+ * so that you can actually send or receive events with them.
+ */
+interface MidiManager { // SINGLETON: Arts_MidiManager
+ /**
+ * a list of clients
+ */
+ readonly attribute sequence<MidiClientInfo> clients;
+
+ /**
+ * add a client
+ *
+ * this creates a new MidiManagerClient
+ */
+ MidiClient addClient(MidiClientDirection direction, MidiClientType type,
+ string title, string autoRestoreID);
+
+ /**
+ * connect two clients
+ */
+ void connect(long clientID, long destinationID);
+
+ /**
+ * disconnect two clients
+ */
+ void disconnect(long clientID, long destinationID);
+
+ /**
+ * add a synchronization group
+ *
+ * this creates a new MidiSyncGroup
+ */
+ MidiSyncGroup addSyncGroup();
+};
+
+interface MidiTest : MidiPort {
+};
+
+interface RawMidiPort : MidiPort {
+ attribute string device;
+ attribute boolean input, output;
+ attribute boolean running;
+ boolean open();
+};
+
+interface AlsaMidiGateway {
+ boolean rescan();
+};
+
+interface AlsaMidiPort : MidiPort {
+ attribute long client;
+ attribute long port;
+ boolean open();
+};
+
+/**
+ * EXPERIMENTAL interface for audio synchronization - this allows multiple
+ * objects to be started and stopped at a precisely defined timestamp
+ */
+interface AudioSync {
+ /**
+ * the current time
+ */
+ readonly attribute TimeStamp time;
+
+ /**
+ * the current play time
+ *
+ * Since aRts has internal buffering, there is a time difference between
+ * where events are currently being rendered, which is the timestamp
+ * obtained by "time", and the events that the listener is hearing right
+ * now, which is this timestamp, the "playTime".
+ */
+ readonly attribute TimeStamp playTime;
+
+ /**
+ * queues calling synthModule.start() later
+ *
+ * (will keep a reference on the module until executed)
+ */
+ void queueStart(SynthModule synthModule);
+
+ /**
+ * queues calling synthModule.stop() later
+ *
+ * (will keep a reference on the module until executed)
+ */
+ void queueStop(SynthModule synthModule);
+
+ /**
+ * atomically executes all queued modification to the flow system
+ */
+ void execute();
+
+ /**
+ * atomically executes all queued modifications to the flow system
+ * at a given time
+ */
+ void executeAt(TimeStamp timeStamp);
+};
+
+/**
+ * Midi Timer - can be used to provide timing for midi ports that have
+ * no "native" timing.
+ */
+interface MidiTimer
+{
+ /**
+ * the current time
+ */
+ readonly attribute TimeStamp time;
+
+ /**
+ * this will put the event into an event queue and send it to the port
+ * once the time for the event has been reached
+ */
+ oneway void queueEvent(MidiPort port, MidiEvent event);
+};
+
+/**
+ * Uses the system time (i.e. gettimeofday() and similar) to provide midi
+ * timing
+ */
+interface SystemMidiTimer : MidiTimer
+{
+};
+
+/**
+ * Uses the audio time (i.e. samples rendered to /dev/dsp) to provide midi
+ * timing
+ */
+interface AudioMidiTimer : MidiTimer
+{
+};
+
+};
diff --git a/arts/midi/audiomiditimer_impl.cc b/arts/midi/audiomiditimer_impl.cc
new file mode 100644
index 00000000..1e39e4f8
--- /dev/null
+++ b/arts/midi/audiomiditimer_impl.cc
@@ -0,0 +1,116 @@
+ /*
+
+ 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 "artsmidi.h"
+#include "artsflow.h"
+#include "stdsynthmodule.h"
+#include "debug.h"
+#include "miditimercommon.h"
+#include "audiotimer.h"
+#include "flowsystem.h"
+
+using namespace std;
+
+namespace Arts {
+
+class AudioMidiTimerCommon : public MidiTimerCommon, public AudioTimerCallback
+{
+protected:
+ AudioMidiTimerCommon();
+ virtual ~AudioMidiTimerCommon();
+
+ AudioTimer *audioTimer;
+
+public:
+ // allocation: share one AudioMidiTimerCommon for everbody who needs one
+ static AudioMidiTimerCommon *subscribe();
+
+ TimeStamp time();
+ void updateTime();
+};
+
+}
+
+using namespace Arts;
+
+static AudioMidiTimerCommon *AudioMidiTimerCommon_the = 0;
+
+AudioMidiTimerCommon::AudioMidiTimerCommon()
+{
+ AudioMidiTimerCommon_the = this;
+
+ audioTimer = AudioTimer::subscribe();
+ audioTimer->addCallback(this);
+}
+
+AudioMidiTimerCommon::~AudioMidiTimerCommon()
+{
+ audioTimer->removeCallback(this);
+ audioTimer->unsubscribe();
+
+ AudioMidiTimerCommon_the = 0;
+}
+
+TimeStamp AudioMidiTimerCommon::time()
+{
+ return audioTimer->time();
+}
+
+void AudioMidiTimerCommon::updateTime()
+{
+ processQueue();
+}
+
+AudioMidiTimerCommon *AudioMidiTimerCommon::subscribe()
+{
+ if(!AudioMidiTimerCommon_the)
+ AudioMidiTimerCommon_the = new AudioMidiTimerCommon();
+ AudioMidiTimerCommon_the->refCount++;
+ return AudioMidiTimerCommon_the;
+}
+
+namespace Arts {
+
+class AudioMidiTimer_impl : public AudioMidiTimer_skel {
+protected:
+ AudioMidiTimerCommon *timer;
+public:
+ AudioMidiTimer_impl()
+ {
+ timer = AudioMidiTimerCommon::subscribe();
+ }
+ ~AudioMidiTimer_impl()
+ {
+ timer->unsubscribe();
+ }
+ TimeStamp time()
+ {
+ return timer->time();
+ }
+ void queueEvent(MidiPort port, const MidiEvent& event)
+ {
+ timer->queueEvent(port, event);
+ }
+};
+
+REGISTER_IMPLEMENTATION(AudioMidiTimer_impl);
+}
diff --git a/arts/midi/audiosync_impl.cc b/arts/midi/audiosync_impl.cc
new file mode 100644
index 00000000..fdba8231
--- /dev/null
+++ b/arts/midi/audiosync_impl.cc
@@ -0,0 +1,203 @@
+ /*
+
+ 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 "audiosync_impl.h"
+#include "midisyncgroup_impl.h"
+#include "audiotimer.h"
+#include "audiosubsys.h"
+#include "timestampmath.h"
+
+#undef AUDIO_DEBUG_DRIFT
+
+using namespace std;
+using namespace Arts;
+
+namespace Arts {
+ static list<AudioSync_impl *> audioSyncImplList;
+}
+
+void AudioSync_impl::AudioSyncEvent::execute()
+{
+ list<SynthModule>::iterator i;
+
+ for(i = startModules.begin(); i != startModules.end(); i++)
+ i->start();
+
+ for(i = stopModules.begin(); i != stopModules.end(); i++)
+ i->stop();
+}
+
+AudioSync_impl::AudioSync_impl()
+ : newEvent(new AudioSyncEvent), syncGroup(0)
+{
+ syncOffset = TimeStamp(0,0);
+
+ timer = AudioTimer::subscribe();
+ timer->addCallback(this);
+
+ audioSyncImplList.push_back(this);
+}
+
+AudioSync_impl::~AudioSync_impl()
+{
+ delete newEvent;
+
+ while(!events.empty())
+ {
+ delete events.front();
+ events.pop_front();
+ }
+
+ if(syncGroup)
+ {
+ syncGroup->audioSyncDied(this);
+ syncGroup = 0;
+ }
+ audioSyncImplList.remove(this);
+ timer->removeCallback(this);
+ timer->unsubscribe();
+}
+
+TimeStamp AudioSync_impl::time()
+{
+ if(syncGroup)
+ return syncGroup->time();
+ else
+ return audioTime();
+}
+
+TimeStamp AudioSync_impl::playTime()
+{
+ if(syncGroup)
+ return syncGroup->playTime();
+ else
+ return audioPlayTime();
+}
+
+TimeStamp AudioSync_impl::audioTime()
+{
+ return timer->time();
+}
+
+TimeStamp AudioSync_impl::audioPlayTime()
+{
+ double delay = AudioSubSystem::the()->outputDelay();
+
+ TimeStamp time = audioTime();
+ timeStampDec(time,timeStampFromDouble(delay));
+ return time;
+}
+
+TimeStamp AudioSync_impl::clientTime()
+{
+ TimeStamp time = audioTime();
+ timeStampDec(time, syncOffset);
+ return time;
+}
+
+void AudioSync_impl::queueStart(SynthModule synthModule)
+{
+ newEvent->startModules.push_back(synthModule);
+}
+
+void AudioSync_impl::queueStop(SynthModule synthModule)
+{
+ newEvent->stopModules.push_back(synthModule);
+}
+
+void AudioSync_impl::execute()
+{
+ newEvent->execute();
+ newEvent->startModules.clear();
+ newEvent->stopModules.clear();
+}
+
+void AudioSync_impl::executeAt(const TimeStamp& timeStamp)
+{
+ newEvent->time = timeStamp;
+ if(syncGroup)
+ timeStampInc(newEvent->time, syncOffset);
+
+ events.push_back(newEvent);
+
+ newEvent = new AudioSyncEvent;
+}
+
+void AudioSync_impl::updateTime()
+{
+ TimeStamp now = audioTime();
+ list<AudioSyncEvent*>::iterator i;
+
+ i = events.begin();
+ while(i != events.end())
+ {
+ AudioSyncEvent *event = *i;
+ TimeStamp& eventTime = event->time;
+
+ if( now.sec > eventTime.sec
+ || ((now.sec == eventTime.sec) && (now.usec > eventTime.usec)))
+ {
+ event->execute();
+ delete event;
+ i = events.erase(i);
+ }
+ else
+ {
+ i++;
+ }
+ }
+}
+
+void AudioSync_impl::setSyncGroup(MidiSyncGroup_impl *newSyncGroup)
+{
+ syncGroup = newSyncGroup;
+}
+
+void AudioSync_impl::synchronizeTo(const TimeStamp& time)
+{
+#ifdef AUDIO_DEBUG_DRIFT
+ TimeStamp drift = syncOffset; // debug drift
+#endif
+
+ syncOffset = audioPlayTime();
+ timeStampDec(syncOffset, time);
+
+#ifdef AUDIO_DEBUG_DRIFT
+ timeStampDec(drift, syncOffset); // debug drift
+ printf("SYNC DRIFT %30s %30s: %f\n",
+ "AudioSync", "AudioSync", timeStampToDouble(drift));
+#endif
+}
+
+AudioSync_impl *AudioSync_impl::find(AudioSync audioSync)
+{
+ list<AudioSync_impl *>::iterator i;
+
+ for(i = audioSyncImplList.begin(); i != audioSyncImplList.end(); i++)
+ {
+ if((*i)->_isEqual(audioSync._base()))
+ return (*i);
+ }
+ return 0;
+}
+
+namespace Arts { REGISTER_IMPLEMENTATION(AudioSync_impl); }
diff --git a/arts/midi/audiosync_impl.h b/arts/midi/audiosync_impl.h
new file mode 100644
index 00000000..835b8942
--- /dev/null
+++ b/arts/midi/audiosync_impl.h
@@ -0,0 +1,79 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef AUDIOSYNC_IMPL_H
+#define AUDIOSYNC_IMPL_H
+
+#include "artsmidi.h"
+#include "audiotimer.h"
+
+namespace Arts {
+
+class MidiSyncGroup_impl;
+class AudioSync_impl : virtual public AudioSync_skel,
+ virtual public AudioTimerCallback
+{
+ AudioTimer *timer;
+
+ struct AudioSyncEvent
+ {
+ TimeStamp time;
+ std::list<SynthModule> startModules;
+ std::list<SynthModule> stopModules;
+
+ void execute();
+ };
+ std::list<AudioSyncEvent *> events;
+ AudioSyncEvent *newEvent;
+ MidiSyncGroup_impl *syncGroup;
+ TimeStamp syncOffset;
+
+ TimeStamp audioTime();
+ TimeStamp audioPlayTime();
+
+public:
+ AudioSync_impl();
+ ~AudioSync_impl();
+
+ // public interface
+ TimeStamp time();
+ TimeStamp playTime();
+
+ void queueStart(SynthModule synthModule);
+ void queueStop(SynthModule synthModule);
+ void execute();
+ void executeAt(const TimeStamp& timeStamp);
+
+ // interface to AudioTimer
+ void updateTime();
+
+ // interface to MidiSyncGroup
+ static AudioSync_impl *find(AudioSync audioSync);
+
+ void synchronizeTo(const TimeStamp& time);
+ void setSyncGroup(MidiSyncGroup_impl *syncGroup);
+ TimeStamp clientTime();
+};
+
+}
+
+#endif /* AUDIOSYNC_IMPL_H */
diff --git a/arts/midi/audiotimer.cc b/arts/midi/audiotimer.cc
new file mode 100644
index 00000000..354f153b
--- /dev/null
+++ b/arts/midi/audiotimer.cc
@@ -0,0 +1,98 @@
+ /*
+
+ 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 "artsmidi.h"
+#include "artsflow.h"
+#include "stdsynthmodule.h"
+#include "debug.h"
+#include "miditimercommon.h"
+#include "audiotimer.h"
+#include "flowsystem.h"
+
+using namespace std;
+using namespace Arts;
+
+static AudioTimer *AudioTimer_the = 0;
+
+AudioTimer::AudioTimer()
+{
+ AudioTimer_the = this;
+ samples = seconds = 0;
+}
+
+AudioTimer::~AudioTimer()
+{
+ AudioTimer_the = 0;
+}
+
+TimeStamp AudioTimer::time()
+{
+ return TimeStamp(seconds,
+ (long)((float)samples / samplingRateFloat * 1000000.0));
+}
+
+void AudioTimer::notify(const Notification &)
+{
+ list<AudioTimerCallback *>::iterator i;
+ for(i = callbacks.begin(); i != callbacks.end(); i++)
+ (*i)->updateTime();
+}
+
+void AudioTimer::calculateBlock(unsigned long s)
+{
+ samples += s;
+ while(samples > samplingRate)
+ {
+ samples -= samplingRate;
+ seconds++;
+ }
+ Notification n;
+ n.receiver = this;
+ n.ID = 0;
+ n.data = 0;
+ n.internal = 0;
+ NotificationManager::the()->send(n);
+}
+
+AudioTimer *AudioTimer::subscribe()
+{
+ if(!AudioTimer_the)
+ {
+ new AudioTimer();
+ AudioTimer_the->_node()->start();
+ }
+ else
+ {
+ AudioTimer_the->_copy();
+ }
+ return AudioTimer_the;
+}
+
+void AudioTimer::addCallback(AudioTimerCallback *callback)
+{
+ callbacks.push_back(callback);
+}
+
+void AudioTimer::removeCallback(AudioTimerCallback *callback)
+{
+ callbacks.remove(callback);
+}
diff --git a/arts/midi/audiotimer.h b/arts/midi/audiotimer.h
new file mode 100644
index 00000000..f0299cf3
--- /dev/null
+++ b/arts/midi/audiotimer.h
@@ -0,0 +1,73 @@
+ /*
+
+ 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.
+
+ */
+#ifndef AUDIOTIMER_H
+#define AUDIOTIMER_H
+
+#include "artsmidi.h"
+#include "artsflow.h"
+#include "stdsynthmodule.h"
+#include "miditimercommon.h"
+#include "flowsystem.h"
+
+namespace Arts {
+
+/**
+ * EXPERIMENTAL (this interface will probably not stay this way) way to handle
+ * audio based time stamps. Callback interface.
+ */
+class AudioTimerCallback {
+public:
+ virtual void updateTime() = 0;
+};
+
+/**
+ * EXPERIMENTAL (this interface will probably not stay this way) way to handle
+ * audio based time stamps. Timer class for audio timestamps.
+ */
+class AudioTimer : public SynthModule_skel, public StdSynthModule
+ /* we are a SynthModule to get the timing */
+{
+protected:
+ AudioTimer();
+ virtual ~AudioTimer();
+
+ std::list<AudioTimerCallback *> callbacks;
+
+ long samples; /* at most samplingRate, overflow goes in seconds */
+ long seconds;
+
+public:
+ // allocation: share one AudioTimer for everbody who needs one
+ static AudioTimer *subscribe();
+ void unsubscribe() { _release(); }
+
+ void notify(const Notification& n);
+ TimeStamp time();
+ void calculateBlock(unsigned long samples);
+
+ void addCallback(AudioTimerCallback *callback);
+ void removeCallback(AudioTimerCallback *callback);
+};
+
+}
+
+#endif
diff --git a/arts/midi/mcopclass/Makefile.am b/arts/midi/mcopclass/Makefile.am
new file mode 100644
index 00000000..5fbeafe8
--- /dev/null
+++ b/arts/midi/mcopclass/Makefile.am
@@ -0,0 +1,2 @@
+mcopclassdir = $(libdir)/mcop/Arts
+mcopclass_DATA = MidiManager.mcopclass
diff --git a/arts/midi/mcopclass/MidiManager.mcopclass b/arts/midi/mcopclass/MidiManager.mcopclass
new file mode 100644
index 00000000..a86af4a4
--- /dev/null
+++ b/arts/midi/mcopclass/MidiManager.mcopclass
@@ -0,0 +1,3 @@
+Interface=Arts::MidiManager,Arts::Object
+Language=C++
+Library=libartsmidi.la
diff --git a/arts/midi/midiclient_impl.cc b/arts/midi/midiclient_impl.cc
new file mode 100644
index 00000000..d57e7fd7
--- /dev/null
+++ b/arts/midi/midiclient_impl.cc
@@ -0,0 +1,274 @@
+ /*
+
+ Copyright (C) 2000-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 "midiclient_impl.h"
+#include "midimanager_impl.h"
+#include "midimanagerport_impl.h"
+#include "midisyncgroup_impl.h"
+#include "timestampmath.h"
+
+#undef DEBUG_SYNC_DRIFT
+
+using namespace Arts;
+using namespace std;
+
+MidiClient_impl::MidiClient_impl(const MidiClientInfo& info,
+ MidiManager_impl *manager) :_info(info), manager(manager), syncGroup(0)
+{
+}
+
+MidiClient_impl::~MidiClient_impl()
+{
+ while(!_info.connections.empty())
+ disconnect(manager->findClient(_info.connections[0]));
+
+ if(syncGroup)
+ {
+ syncGroup->clientDied(this);
+ syncGroup = 0;
+ }
+ manager->removeClient(this);
+}
+
+MidiClientInfo MidiClient_impl::info()
+{
+ return _info;
+}
+
+void MidiClient_impl::title(const string &newvalue)
+{
+ _info.title = newvalue;
+}
+
+string MidiClient_impl::title()
+{
+ return _info.title;
+}
+
+void MidiClient_impl::addInputPort(MidiPort port)
+{
+ assert(_info.direction == mcdRecord);
+
+ ports.push_back(port);
+
+ // FIXME: should we synchronize inputPorts at all
+ rebuildConnections();
+}
+
+MidiPort MidiClient_impl::addOutputPort()
+{
+ assert(_info.direction == mcdPlay);
+
+ MidiPort port = MidiPort::_from_base(new MidiManagerPort_impl(this));
+ ports.push_back(port);
+
+ rebuildConnections();
+ return port;
+}
+
+void MidiClient_impl::removePort(MidiPort port)
+{
+ list<MidiPort>::iterator i = ports.begin();
+ while(i != ports.end())
+ {
+ if (i->_isEqual(port))
+ i = ports.erase(i);
+ else
+ i++;
+ }
+
+ rebuildConnections();
+}
+
+void MidiClient_impl::rebuildConnections()
+{
+ _connections.clear();
+
+ vector<long>::iterator li;
+ for(li = _info.connections.begin(); li != _info.connections.end(); li++)
+ {
+ MidiClient_impl *other = manager->findClient(*li);
+ assert(other);
+
+ list<MidiPort>::iterator pi;
+ for(pi = other->ports.begin(); pi != other->ports.end(); pi++)
+ {
+ MidiClientConnection mcc;
+ mcc.offset = TimeStamp(0,0);
+ mcc.port = *pi;
+ _connections.push_back(mcc);
+ }
+ }
+ adjustSync();
+}
+
+list<MidiClientConnection> *MidiClient_impl::connections()
+{
+ return &_connections;
+}
+
+static void removeElement(vector<long>& vec, long el)
+{
+ vector<long> tmp;
+ vec.swap(tmp);
+ vector<long>::iterator i;
+ for(i = tmp.begin(); i != tmp.end(); i++)
+ if(*i != el) vec.push_back(*i);
+}
+
+void MidiClient_impl::connect(MidiClient_impl *dest)
+{
+ assert(_info.direction != dest->_info.direction);
+
+ disconnect(dest);
+
+ _info.connections.push_back(dest->ID());
+ dest->_info.connections.push_back(ID());
+
+ list<MidiPort>::iterator pi;
+
+ /* add the other clients ports to our connection list */
+ for(pi = dest->ports.begin(); pi != dest->ports.end(); pi++)
+ {
+ MidiClientConnection mcc;
+ mcc.offset = TimeStamp(0,0);
+ mcc.port = *pi;
+ _connections.push_back(mcc);
+ }
+
+ /* add our ports to the other clients connection list */
+ for(pi = ports.begin(); pi != ports.end(); pi++)
+ {
+ MidiClientConnection mcc;
+ mcc.offset = TimeStamp(0,0);
+ mcc.port = *pi;
+ dest->_connections.push_back(mcc);
+ }
+ adjustSync();
+}
+
+void MidiClient_impl::disconnect(MidiClient_impl *dest)
+{
+ assert(_info.direction != dest->_info.direction);
+
+ removeElement(_info.connections,dest->ID());
+ removeElement(dest->_info.connections,ID());
+
+ list<MidiPort>::iterator pi;
+
+ /* remove the other clients ports from our connection list */
+ for(pi = dest->ports.begin(); pi != dest->ports.end(); pi++)
+ {
+ list<MidiClientConnection>::iterator ci = _connections.begin();
+
+ while(ci != _connections.end())
+ {
+ if(ci->port._isEqual(*pi))
+ ci = _connections.erase(ci);
+ else
+ ci++;
+ }
+ }
+
+ /* remove our ports from the other clients connection list */
+ for(pi = ports.begin(); pi != ports.end(); pi++)
+ {
+ list<MidiClientConnection>::iterator ci = dest->_connections.begin();
+
+ while(ci != dest->_connections.end())
+ {
+ if(ci->port._isEqual(*pi))
+ ci = dest->_connections.erase(ci);
+ else
+ ci++;
+ }
+ }
+ adjustSync();
+}
+
+void MidiClient_impl::synchronizeTo(const TimeStamp& time)
+{
+ list<MidiClientConnection>::iterator i;
+
+ for(i = _connections.begin(); i != _connections.end(); i++)
+ {
+ MidiClientConnection& mcc = *i;
+
+#ifdef DEBUG_SYNC_DRIFT
+ TimeStamp drift = mcc.offset; // debug drift
+#endif
+
+ mcc.offset = mcc.port.playTime();
+ timeStampDec(mcc.offset, time);
+
+#ifdef DEBUG_SYNC_DRIFT
+ timeStampDec(drift,mcc.offset); // debug drift
+ printf("SYNC DRIFT %30s %30s: %f\n",
+ mcc.port._interfaceName().c_str(), _info.title.c_str(),
+ timeStampToDouble(drift));
+#endif
+ }
+}
+
+void MidiClient_impl::setSyncGroup(MidiSyncGroup_impl *newSyncGroup)
+{
+ syncGroup = newSyncGroup;
+}
+
+void MidiClient_impl::adjustSync()
+{
+ if(syncGroup)
+ syncGroup->clientChanged(this);
+ else
+ synchronizeTo(systemMidiTimer.time());
+}
+
+TimeStamp MidiClient_impl::time()
+{
+ if(syncGroup)
+ return syncGroup->time();
+ else
+ return clientTime();
+}
+
+TimeStamp MidiClient_impl::playTime()
+{
+ if(syncGroup)
+ return syncGroup->playTime();
+ else
+ return systemMidiTimer.time();
+}
+
+TimeStamp MidiClient_impl::clientTime()
+{
+ TimeStamp result = playTime();
+
+ list<MidiClientConnection>::iterator i;
+ for(i = _connections.begin(); i != _connections.end(); i++)
+ {
+ TimeStamp time = i->port.time();
+ timeStampDec(time, i->offset);
+ result = timeStampMax(result, time);
+ }
+
+ return result;
+}
diff --git a/arts/midi/midiclient_impl.h b/arts/midi/midiclient_impl.h
new file mode 100644
index 00000000..b1aeb204
--- /dev/null
+++ b/arts/midi/midiclient_impl.h
@@ -0,0 +1,80 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef ARTS_MIDICLIENT_IMPL_H
+#define ARTS_MIDICLIENT_IMPL_H
+
+#include "artsmidi.h"
+#include "midimanager_impl.h"
+#include "midimanagerport_impl.h"
+
+namespace Arts {
+
+struct MidiClientConnection
+{
+ TimeStamp offset;
+ MidiPort port;
+};
+
+class MidiManager_impl;
+class MidiSyncGroup_impl;
+class MidiClient_impl : virtual public MidiClient_skel
+{
+protected:
+ SystemMidiTimer systemMidiTimer;
+ MidiClientInfo _info;
+ MidiManager_impl *manager;
+ MidiSyncGroup_impl *syncGroup;
+ std::list<MidiPort> ports;
+ std::list<MidiClientConnection> _connections;
+
+public:
+ MidiClient_impl(const MidiClientInfo& info, MidiManager_impl *manager);
+ ~MidiClient_impl();
+
+ // MCOP interface
+ MidiClientInfo info();
+ void title(const std::string &newvalue);
+ std::string title();
+ void addInputPort(MidiPort port);
+ MidiPort addOutputPort();
+ void removePort(MidiPort port);
+
+ // interface to MidiManager/Port
+ inline long ID() { return _info.ID; }
+ std::list<MidiClientConnection> *connections();
+ void connect(MidiClient_impl *dest);
+ void disconnect(MidiClient_impl *dest);
+ void rebuildConnections();
+ void adjustSync();
+
+ TimeStamp time();
+ TimeStamp playTime();
+
+ // interface to MidiSyncGroup
+ void synchronizeTo(const TimeStamp& time);
+ void setSyncGroup(MidiSyncGroup_impl *syncGroup);
+ TimeStamp clientTime();
+};
+
+}
+#endif /* ARTS_MIDICLIENT_IMPL_H */
diff --git a/arts/midi/midimanager_impl.cc b/arts/midi/midimanager_impl.cc
new file mode 100644
index 00000000..1ba07962
--- /dev/null
+++ b/arts/midi/midimanager_impl.cc
@@ -0,0 +1,156 @@
+ /*
+
+ 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 "midimanager_impl.h"
+#include "midiclient_impl.h"
+#include "midisyncgroup_impl.h"
+#include "debug.h"
+
+using namespace Arts;
+using namespace std;
+
+static int cleanReference(const string& reference)
+{
+ Object test = Reference("global:"+reference);
+ if(test.isNull())
+ {
+ Dispatcher::the()->globalComm().erase(reference);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+MidiManager_impl::MidiManager_impl() : nextID(1)
+{
+ cleanReference("Arts_MidiManager");
+ if(!ObjectManager::the()->addGlobalReference(Object::_from_base(_copy()),
+ "Arts_MidiManager"))
+ {
+ arts_warning("can't register Arts::MidiManager");
+ }
+ else
+ {
+ arts_debug("Arts::MidiManager registered successfully.");
+ }
+ Dispatcher::the()->ioManager()->addTimer(1000, this);
+}
+
+MidiManager_impl::~MidiManager_impl()
+{
+ Dispatcher::the()->ioManager()->removeTimer(this);
+}
+
+vector<MidiClientInfo> *MidiManager_impl::clients()
+{
+ if(!alsaMidiGateway.isNull())
+ {
+ if(!alsaMidiGateway.rescan())
+ alsaMidiGateway = AlsaMidiGateway::null();
+ }
+
+ vector<MidiClientInfo> *result = new vector<MidiClientInfo>;
+
+ list<MidiClient_impl *>::iterator i;
+ for(i = _clients.begin(); i != _clients.end(); i++)
+ result->push_back((*i)->info());
+
+ return result;
+}
+
+MidiClient MidiManager_impl::addClient(MidiClientDirection direction,
+ MidiClientType type, const string& title, const string& autoRestoreID)
+{
+ MidiClientInfo info;
+
+ info.ID = nextID++;
+ info.direction = direction;
+ info.type = type;
+ info.title = title;
+ info.autoRestoreID = autoRestoreID;
+
+ MidiClient_impl *impl = new MidiClient_impl(info, this);
+ _clients.push_back(impl);
+ return MidiClient::_from_base(impl);
+}
+
+void MidiManager_impl::removeClient(MidiClient_impl *client)
+{
+ _clients.remove(client);
+}
+
+MidiClient_impl *MidiManager_impl::findClient(long clientID)
+{
+ list<MidiClient_impl *>::iterator i;
+
+ for(i = _clients.begin(); i != _clients.end(); i++)
+ {
+ if((*i)->ID() == clientID)
+ return (*i);
+ }
+ return 0;
+}
+
+void MidiManager_impl::connect(long clientID, long destinationID)
+{
+ MidiClient_impl *src = findClient(clientID);
+ MidiClient_impl *dest = findClient(destinationID);
+
+ arts_return_if_fail(src);
+ arts_return_if_fail(dest);
+ src->connect(dest);
+}
+
+void MidiManager_impl::disconnect(long clientID, long destinationID)
+{
+ MidiClient_impl *src = findClient(clientID);
+ MidiClient_impl *dest = findClient(destinationID);
+
+ arts_return_if_fail(src);
+ arts_return_if_fail(dest);
+ src->disconnect(dest);
+}
+
+MidiSyncGroup MidiManager_impl::addSyncGroup()
+{
+ MidiSyncGroup_impl *impl = new MidiSyncGroup_impl(this);
+ syncGroups.push_back(impl);
+ return MidiSyncGroup::_from_base(impl);
+}
+
+void MidiManager_impl::removeSyncGroup(MidiSyncGroup_impl *group)
+{
+ syncGroups.remove(group);
+}
+
+void MidiManager_impl::notifyTime()
+{
+ list<MidiClient_impl *>::iterator i;
+ for(i = _clients.begin(); i != _clients.end(); i++)
+ (*i)->adjustSync();
+
+ list<MidiSyncGroup_impl *>::iterator gi;
+ for(gi = syncGroups.begin(); gi != syncGroups.end(); gi++)
+ (*gi)->adjustSync();
+}
+
+namespace Arts { REGISTER_IMPLEMENTATION(MidiManager_impl); }
diff --git a/arts/midi/midimanager_impl.h b/arts/midi/midimanager_impl.h
new file mode 100644
index 00000000..0c9ec5df
--- /dev/null
+++ b/arts/midi/midimanager_impl.h
@@ -0,0 +1,67 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef ARTS_MIDIMANAGER_IMPL_H
+#define ARTS_MIDIMANAGER_IMPL_H
+
+#include "artsmidi.h"
+
+namespace Arts {
+
+class MidiClient_impl;
+class MidiSyncGroup_impl;
+class MidiManager_impl : virtual public MidiManager_skel,
+ virtual public TimeNotify
+{
+protected:
+ std::list<MidiClient_impl *> _clients;
+ std::list<MidiSyncGroup_impl *> syncGroups;
+
+ long nextID;
+ AlsaMidiGateway alsaMidiGateway;
+
+ void notifyTime();
+
+public:
+ MidiManager_impl();
+ ~MidiManager_impl();
+
+ // public interface
+ std::vector<MidiClientInfo> *clients();
+
+ MidiClient addClient(MidiClientDirection direction, MidiClientType type,
+ const std::string& title, const std::string& autoRestoreID);
+
+ void connect(long clientID, long destinationID);
+ void disconnect(long clientID, long destinationID);
+ MidiSyncGroup addSyncGroup();
+
+ // interface to MidiClient_impl
+ void removeClient(MidiClient_impl *client);
+ MidiClient_impl *findClient(long clientID);
+
+ // interface to MidiSyncGroup_impl
+ void removeSyncGroup(MidiSyncGroup_impl *group);
+};
+
+}
+#endif /* ARTS_MIDIMANAGER_IMPL_H */
diff --git a/arts/midi/midimanagerport_impl.cc b/arts/midi/midimanagerport_impl.cc
new file mode 100644
index 00000000..a6973a51
--- /dev/null
+++ b/arts/midi/midimanagerport_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 "midimanagerport_impl.h"
+#include "midimanager_impl.h"
+#include "midiclient_impl.h"
+#include "timestampmath.h"
+
+#include <stdio.h>
+
+using namespace Arts;
+using namespace std;
+
+MidiManagerPort_impl::MidiManagerPort_impl(MidiClient_impl *client)
+ : client(client)
+{
+}
+
+TimeStamp MidiManagerPort_impl::time()
+{
+ return client->time();
+}
+
+TimeStamp MidiManagerPort_impl::playTime()
+{
+ return client->playTime();
+}
+
+
+void MidiManagerPort_impl::processCommand(const MidiCommand& command)
+{
+ list<MidiClientConnection> *connections = client->connections();
+ list<MidiClientConnection>::iterator i;
+
+ for(i = connections->begin(); i != connections->end(); i++)
+ i->port.processCommand(command);
+}
+
+void MidiManagerPort_impl::processEvent(const MidiEvent& event)
+{
+ list<MidiClientConnection> *connections = client->connections();
+ list<MidiClientConnection>::iterator i;
+
+ for(i = connections->begin(); i != connections->end(); i++)
+ {
+ /* relocate the event to the synchronized time */
+ TimeStamp time = event.time;
+ timeStampInc(time, i->offset);
+
+ i->port.processEvent(MidiEvent(time, event.command));
+ }
+}
diff --git a/arts/midi/midimanagerport_impl.h b/arts/midi/midimanagerport_impl.h
new file mode 100644
index 00000000..56998546
--- /dev/null
+++ b/arts/midi/midimanagerport_impl.h
@@ -0,0 +1,46 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef MIDIMANAGERPORT_IMPL_H
+#define MIDIMANAGERPORT_IMPL_H
+
+#include "artsmidi.h"
+
+namespace Arts {
+
+class MidiClient_impl;
+
+class MidiManagerPort_impl : public MidiPort_skel
+{
+ MidiClient_impl *client;
+ SystemMidiTimer timer;
+public:
+ MidiManagerPort_impl(MidiClient_impl *client);
+ TimeStamp time();
+ TimeStamp playTime();
+ void processCommand(const MidiCommand& command);
+ void processEvent(const MidiEvent& event);
+};
+
+}
+
+#endif /* MIDIMANAGERPORT_IMPL_H */
diff --git a/arts/midi/midimsg.c b/arts/midi/midimsg.c
new file mode 100644
index 00000000..7032fba8
--- /dev/null
+++ b/arts/midi/midimsg.c
@@ -0,0 +1,177 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "midimsg.h"
+
+#define STATUS_MASK 0x80
+#define MESSAGE_TYPE_MASK 0xf0
+#define CHANNEL_MASK 0x0f
+
+Byte midiReadByte(int fd)
+{
+ Byte current_byte;
+ /*
+ ** for now ignore all realtime-messages (0xF8 .. 0xFF), which may get
+ ** embedded *inside* every other message
+ */
+ do {
+ /*
+ ** read() is wrapped in a while() in order to handle interruption
+ ** by a signal. In the normal case, read() is only called once.
+ */
+ while (read(/* fd = */ fd, /* buf = */ (void *)(&current_byte),
+ /* count = */ 1) < 1) {}
+
+ } while(current_byte >= 0xf8);
+
+ return current_byte;
+}
+
+int midimsgGetMessageType(Byte *message)
+{
+ return (message[0] & MESSAGE_TYPE_MASK);
+}
+
+void midimsgSetMessageType(Byte *message_inout, int message_type)
+{
+ message_inout[0] = (message_inout[0] & ~MESSAGE_TYPE_MASK) | message_type;
+}
+
+int midimsgGetChannel(Byte *message)
+{
+ return (message[0] & CHANNEL_MASK);
+}
+
+void midimsgSetChannel(Byte *message_inout, int channel)
+{
+ message_inout[0] = (message_inout[0] & ~CHANNEL_MASK) | channel;
+}
+
+int midimsgGetPitch(Byte *message)
+{
+ return (message[1]);
+}
+
+void midimsgSetPitch(Byte *message_inout, int pitch)
+{
+ message_inout[1] = pitch;
+}
+
+int midimsgGetVelocity(Byte *message)
+{
+ return (message[2]);
+}
+
+void midimsgSetVelocity(Byte *message_inout, int velocity)
+{
+ message_inout[2] = velocity;
+}
+
+int midimsgGetParameterNumber(Byte *message)
+{
+ return (message[1]);
+}
+
+void midimsgSetParameterNumber(Byte *message_inout, int number)
+{
+ message_inout[1] = number;
+}
+
+int midimsgGetParameterValue(Byte *message)
+{
+ return (message[2]);
+}
+
+void midimsgSetParameterValue(Byte *message_inout, int value)
+{
+ message_inout[2] = value;
+}
+
+int midimsgGetPitchWheelValue(Byte *message)
+{
+ return (((int)(message[2]) << 7) + message[1]);
+}
+
+void midimsgRead(int fd, Byte *message_return)
+{
+ Byte current_byte;
+ static Byte last_status_byte;
+
+ current_byte = midiReadByte(fd);
+
+ if ((current_byte & STATUS_MASK) == 0)
+ {
+ /*
+ ** must be a running status, unless we're picking up mid-message
+ ** (which would be an unhandled error)
+ */
+
+ message_return[0] = last_status_byte;
+ }
+ else
+ {
+ message_return[0] = current_byte;
+ last_status_byte = current_byte;
+
+ current_byte = midiReadByte(fd);
+ }
+
+ switch (midimsgGetMessageType(/* message = */ message_return))
+ {
+ case MIDIMSG_NOTE_ON:
+ case MIDIMSG_NOTE_OFF:
+ case MIDIMSG_KEY_PRESSURE:
+ case MIDIMSG_PARAMETER:
+ case MIDIMSG_PITCH_WHEEL:
+
+ message_return[1] = current_byte;
+
+ current_byte = midiReadByte(fd);
+ message_return[2] = current_byte;
+
+ if ((midimsgGetMessageType(/* message = */ message_return) ==
+ MIDIMSG_NOTE_ON) && (midimsgGetVelocity(/* message = */
+ message_return) == 0))
+ {
+ /* note-on with velocity of zero is equivalent to note-off */
+
+ midimsgSetMessageType(/* message_inout = */ message_return,
+ /* message_type = */ MIDIMSG_NOTE_OFF);
+ }
+
+ return;
+
+ case MIDIMSG_PROGRAM:
+ case MIDIMSG_CHANNEL_PRESSURE:
+
+ message_return[1] = current_byte;
+
+ return;
+ }
+}
+
+void midimsgWrite(int fd, Byte *message)
+{
+ switch (midimsgGetMessageType(/* message = */ message))
+ {
+ case MIDIMSG_NOTE_ON:
+ case MIDIMSG_NOTE_OFF:
+ case MIDIMSG_KEY_PRESSURE:
+ case MIDIMSG_PARAMETER:
+ case MIDIMSG_PITCH_WHEEL:
+ write(fd, message, 3);
+ break;
+ case MIDIMSG_PROGRAM:
+ case MIDIMSG_CHANNEL_PRESSURE:
+ write(fd, message, 2);
+ break;
+ }
+}
+
diff --git a/arts/midi/midimsg.h b/arts/midi/midimsg.h
new file mode 100644
index 00000000..3bba90d7
--- /dev/null
+++ b/arts/midi/midimsg.h
@@ -0,0 +1,44 @@
+
+#ifndef MIDIMSG_H
+#define MIDIMSG_H
+
+typedef unsigned char Byte;
+
+#define MIDIMSG_NOTE_OFF 0x80
+#define MIDIMSG_NOTE_ON 0x90
+#define MIDIMSG_KEY_PRESSURE 0xa0
+#define MIDIMSG_PARAMETER 0xb0
+#define MIDIMSG_PROGRAM 0xc0
+#define MIDIMSG_CHANNEL_PRESSURE 0xd0
+#define MIDIMSG_PITCH_WHEEL 0xe0
+
+#ifndef True
+#define True 1
+#define False 0
+#endif
+
+int midimsgGetMessageType(Byte *message);
+void midimsgSetMessageType(Byte *message_inout, int message_type);
+
+int midimsgGetChannel(Byte *message);
+void midimsgSetChannel(Byte *message_inout, int channel);
+
+int midimsgGetPitch(Byte *message);
+void midimsgSetPitch(Byte *message_inout, int pitch);
+
+int midimsgGetVelocity(Byte *message);
+void midimsgSetVelocity(Byte *message_inout, int velocity);
+
+int midimsgGetParameterNumber(Byte *message);
+void midimsgSetParameterNumber(Byte *message_inout, int number);
+
+int midimsgGetParameterValue(Byte *message);
+void midimsgSetParameterValue(Byte *message_inout, int value);
+
+int midimsgGetPitchWheelValue(Byte *message);
+
+void midimsgRead(int fd, Byte *message_return);
+void midimsgWrite(int fd, Byte *message_return);
+
+#endif
+
diff --git a/arts/midi/midisend.cc b/arts/midi/midisend.cc
new file mode 100644
index 00000000..2c1878ef
--- /dev/null
+++ b/arts/midi/midisend.cc
@@ -0,0 +1,375 @@
+/*
+
+Copyright (C) 1999 Emmeran Seehuber
+ the_emmy@gmx.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.
+
+*/
+
+/*
+ Changes:
+ 16.09.1999 Emmeran "Emmy" Seehuber <the_emmy@gmx.de>
+ - Implementeted mapping of channels and pitches.
+ - Reworked option parsing, now using getopt().
+ Note: The parameters of the programms have changed !
+*/
+
+/*
+** This program was in original by David G. Slomin.
+** It was released to the Public Domain on 1/25/99.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "midisend.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+using namespace std;
+
+int input_fd = -1, test = 0, verbose = 0;
+char cFileName[1025];
+int optch;
+CMidiMap Map;
+
+void usage(char *prog)
+{
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Usage: %s [ -f <mididevice> ] [ -m <mapfile> ] [ -v ] [ -t <loop> ]\n",prog);
+ fprintf(stderr," -f the mididevice to read the input from.\n");
+ fprintf(stderr," Default is /dev/midi. If you specify a dash, it is stdin\n");
+ fprintf(stderr," -m the mapfile to load.\n");
+ fprintf(stderr," -v verbose output.\n");
+ fprintf(stderr," -t test mode. Generates a testoutput on the midibus\n");
+ fprintf(stderr," -l long test mode. Generates a testoutput on the midibus\n");
+ exit(1);
+}
+
+void parseArgs(int argc, char** argv)
+{
+ // Setup default
+ strcpy(cFileName,"/dev/midi");
+
+ while((optch = getopt(argc,argv,"m:f:vtl")) > 0)
+ {
+ switch(optch)
+ {
+ case 'm': if( !Map.readMap(optarg) )
+ fprintf(stderr,"%s: can't read file %s!\n",argv[0],optarg);
+ break;
+ case 't': test = 1;
+ break;
+ case 'l': test = 2;
+ break;
+#ifdef VERSION
+ case 'v': verbose = 1; printf("MidiSend %s\n", VERSION );
+ break;
+#endif
+ case 'f': strncpy(cFileName,optarg,1024);
+ break;
+ default: usage(argv[0]);
+ break;
+ }
+ }
+}
+
+
+#ifdef COMMON_BINARY
+int midisend_main(int argc, char *argv[])
+#else
+int main(int argc, char *argv[])
+#endif
+{
+ Arts::Dispatcher dispatcher;
+ Arts::MidiManager manager = Arts::Reference("global:Arts_MidiManager");
+
+ if (manager.isNull())
+ {
+ fprintf(stderr, "%s trouble: No midimanager object found; please start "
+ "artsd.\n",argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ ** MIDI input initialization.
+ */
+
+ parseArgs(argc,argv);
+
+ string title = string("midisend (") + cFileName +")";
+ Arts::MidiClient client
+ = manager.addClient(Arts::mcdPlay,Arts::mctApplication,title,"midisend");
+ Arts::MidiPort port = client.addOutputPort();
+
+ if(test)
+ {
+ if( verbose )
+ printf("performing test ...\n");
+ unsigned long i,max=5000;
+ if(test==2) max = 20000;
+ for(i=0;i<max;i++)
+ {
+ port.processCommand(
+ Arts::MidiCommand(Arts::mcsNoteOn, 60+(i%12), 100));
+ port.processCommand(
+ Arts::MidiCommand(Arts::mcsNoteOff,60+(i%12), 0));
+ }
+ exit(0);
+ }
+
+ if( verbose )
+ printf("trying to open %s ...", cFileName );
+
+ input_fd = open(cFileName,O_RDONLY);
+
+ if(input_fd == -1)
+ {
+ fprintf(stderr,"\n%s trouble: can't open input device!\n",argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ else if( verbose )
+ printf(" ok!\n");
+
+
+ /*
+ ** Main loop.
+ */
+
+ if(verbose)
+ printf("beginning loop ...\n");
+
+ unsigned char msg[3];
+
+ while (1)
+ {
+ midimsgRead(input_fd, msg);
+ switch (midimsgGetMessageType(msg))
+ {
+ case MIDIMSG_NOTE_OFF:
+ Map.mapMsg(msg);
+ port.processCommand(
+ Arts::MidiCommand(Arts::mcsNoteOff|midimsgGetChannel(msg),
+ midimsgGetPitch(msg), midimsgGetVelocity(msg)));
+ if( verbose )
+ printf("NoteOff: Channel %d, Pitch %3d\n", midimsgGetChannel(msg),midimsgGetPitch(msg));
+ break;
+ case MIDIMSG_NOTE_ON:
+ Map.mapMsg(msg);
+ port.processCommand(
+ Arts::MidiCommand(Arts::mcsNoteOn|midimsgGetChannel(msg),
+ midimsgGetPitch(msg), midimsgGetVelocity(msg)));
+ if( verbose )
+ printf("NoteOn : Channel %d, Pitch %3d, Velocity %2d\n", midimsgGetChannel(msg),
+ midimsgGetPitch(msg),midimsgGetVelocity(msg));
+ break;
+ case MIDIMSG_PITCH_WHEEL:
+ Map.mapMsg(msg);
+ port.processCommand(
+ Arts::MidiCommand(Arts::mcsPitchWheel|midimsgGetChannel(msg),
+ midimsgGetPitch(msg), midimsgGetVelocity(msg)));
+ if( verbose )
+ printf("PitchWheel : Channel %d, LSB %3d MSB %3d\n", midimsgGetChannel(msg),
+ midimsgGetPitch(msg),midimsgGetVelocity(msg));
+ break;
+ }
+ }
+}
+
+//--------------------------------------------
+// The mapping stuff
+//--------------------------------------------
+
+bool CMidiMap::readMap(const char* pszFileName)
+{
+ if( verbose )
+ printf("reading mapfile %s ...\n", pszFileName);
+
+ FILE *file = fopen(pszFileName,"r");
+ if( !file )
+ return false;
+
+ char cBuffer[1024+1];
+ char* pszLine;
+ int nLine = 0;
+ while( (pszLine = fgets(cBuffer,1024,file)) ) {
+ nLine++;
+ parseLine(pszLine,pszFileName,nLine);
+ }
+ fclose(file);
+
+ return true;
+}
+
+bool CMidiMap::getNextWord(char*& pszLine, char*& pszWord)
+{
+ // First skip all leading blanks, etc.
+ bool bCont = true;
+ while(bCont) {
+ char cHelp = *pszLine;
+ switch( cHelp )
+ {
+ case 0: return false; // Out of line
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\t': pszLine++; break; // Goto next char
+ default: bCont = false; break; // NonSpace character -> Word begins here.
+ }
+ }
+
+ // The word starts here
+ pszWord = pszLine;
+
+ // And now, goto the end of the word.
+ bCont = true;
+ while(bCont) {
+ char cHelp = *pszLine;
+ switch( cHelp )
+ {
+ case 0:
+ case ',':
+ case ';':
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\t': *pszLine++ = 0; bCont = false; break; // Goto next char
+ default: pszLine++; break;
+ }
+ }
+
+ return true;
+}
+
+void CMidiMap::parseLine(char* pszLine, const char* pszConfigFile, int nConfigLine )
+{
+ char* pszWord = 0;
+ bool bOk = true;
+
+ // Get first word of the line
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ if( !bOk )
+ return;
+
+ // Skip comments
+ if( *pszWord == '#' )
+ return;
+
+ if( strcmp(pszWord,"PRC") == 0 ) {
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nOrigChannel = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nStart = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nEnd = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nChannel = atol(pszWord);
+ if( bOk ) {
+ channelMaps[nOrigChannel].nChannel = nOrigChannel;
+ for( int i = nStart; i <= nEnd; i++ ) {
+ channelMaps[nOrigChannel].channelRemaps[i].nPitch = i;
+ channelMaps[nOrigChannel].channelRemaps[i].nChannel = nChannel;
+ }
+ }
+ else {
+ printf("midisend: (PRC) missing parameters at %s:%d\n", pszConfigFile,nConfigLine);
+ }
+ return;
+ }
+
+ if( strcmp(pszWord,"PRD") == 0 ) {
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nOrigChannel = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nStart = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nEnd = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nPitchDiff = atol(pszWord);
+ if( bOk ) {
+ channelMaps[nOrigChannel].nChannel = nOrigChannel;
+ for( int i = nStart; i <= nEnd; i++ ) {
+ channelMaps[nOrigChannel].pitchRemaps[i].nPitch = i;
+ channelMaps[nOrigChannel].pitchRemaps[i].nToPitch = i + nPitchDiff;
+ }
+ }
+ else {
+ printf("midisend: (PRD) missing parameters at %s:%d\n", pszConfigFile,nConfigLine);
+ }
+ return;
+ }
+
+ if( strcmp(pszWord,"PTC") == 0 ) {
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nOrigChannel = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nPitch = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nToChannel = atol(pszWord);
+ if( bOk ) {
+ channelMaps[nOrigChannel].nChannel = nOrigChannel;
+ channelMaps[nOrigChannel].channelRemaps[nPitch].nPitch = nPitch;
+ channelMaps[nOrigChannel].channelRemaps[nPitch].nChannel = nToChannel;
+ }
+ else {
+ printf("midisend: (PTC) missing parameters at %s:%d\n", pszConfigFile,nConfigLine);
+ }
+ return;
+ }
+
+ if( strcmp(pszWord,"PTP") == 0 ) {
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nOrigChannel = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nPitch = atol(pszWord);
+ bOk = bOk && getNextWord(pszLine,pszWord);
+ int nToPitch = atol(pszWord);
+ if( bOk ) {
+ channelMaps[nOrigChannel].nChannel = nOrigChannel;
+ channelMaps[nOrigChannel].pitchRemaps[nPitch].nPitch = nPitch;
+ channelMaps[nOrigChannel].pitchRemaps[nPitch].nToPitch = nToPitch;
+ }
+ else {
+ printf("midisend: (PTP) missing parameters at %s:%d\n", pszConfigFile,nConfigLine);
+ }
+ return;
+ }
+
+ printf("midisend: Unknown command at %s:%d\n", pszConfigFile,nConfigLine);
+}
+
+void CMidiMap::mapMsg(Byte* msg)
+{
+ // Get out the data for mapping
+ int nChannel = midimsgGetChannel(msg);
+ int nPitch = midimsgGetPitch(msg);
+
+ // Is there something to map for this channel ?
+ if( channelMaps.find(nChannel) != channelMaps.end() ) {
+ // => Yes, than do it.
+
+ // C/P => C
+ if( channelMaps[nChannel].channelRemaps.find(nPitch) != channelMaps[nChannel].channelRemaps.end() )
+ midimsgSetChannel(msg,channelMaps[nChannel].channelRemaps[nPitch].nChannel);
+
+ // C/P => P
+ if( channelMaps[nChannel].pitchRemaps.find(nPitch) != channelMaps[nChannel].pitchRemaps.end() ) {
+ midimsgSetPitch(msg,channelMaps[nChannel].pitchRemaps[nPitch].nToPitch);
+ }
+ }
+}
diff --git a/arts/midi/midisend.h b/arts/midi/midisend.h
new file mode 100644
index 00000000..817ebfa2
--- /dev/null
+++ b/arts/midi/midisend.h
@@ -0,0 +1,106 @@
+/*
+
+Copyright (C) 1999 Emmeran Seehuber
+ the_emmy@gmx.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.
+
+*/
+#ifndef MIDISEND_H
+#define MIDISEND_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "artsmidi.h"
+#include <vector>
+#include <iostream>
+#include <string>
+
+extern "C"
+{
+#include "midimsg.h"
+}
+
+/*
+ This class does the mapping of the
+ channels and pitches
+*/
+class CMidiMap {
+public:
+ /*
+ Reads in the mapfile pszFileName.
+ Returns TRUE, if successful.
+ */
+ bool readMap(const char* pszFileName);
+ /*
+ Maps the given message according to
+ the actual read configuration.
+ */
+ void mapMsg(Byte* msg);
+
+private:
+ /*
+ Parses a configuration line.
+ */
+ void parseLine(char* pszLine, const char* pszConfigFile, int nConfigLine );
+
+ /*
+ Gets the next word out of the line. throws
+ the exception CEOutOfLine, if there is no
+ more word in the line.
+
+ A word consists of all but \0, spacecharacter, ';' and
+ ','
+
+ pszLine is the pointer to the start of the
+ line. This function modifies the pointer.
+ pszWord is the pointer to the found word.
+ */
+ bool getNextWord(char*& pszLine, char*& pszWord);
+private:
+
+ /*
+ For each channel one instance of this structure
+ exists in the channelMaps. It holds the mapping information
+ for nChannel.
+ */
+ struct ChannelMaps {
+ int nChannel;
+
+ struct ChannelRemap {
+ int nPitch;
+ int nChannel;
+ };
+
+ struct PitchRemap {
+ int nPitch;
+ int nToPitch;
+ };
+
+ typedef std::map<int,ChannelRemap> ChannelRemapMap;
+ ChannelRemapMap channelRemaps;
+ typedef std::map<int,PitchRemap> PitchRemapMap;
+ PitchRemapMap pitchRemaps;
+ };
+ typedef std::map<int,ChannelMaps> ChannelMapsMap;
+ ChannelMapsMap channelMaps;
+};
+
+
+#endif
diff --git a/arts/midi/midisyncgroup_impl.cc b/arts/midi/midisyncgroup_impl.cc
new file mode 100644
index 00000000..57ebca2c
--- /dev/null
+++ b/arts/midi/midisyncgroup_impl.cc
@@ -0,0 +1,125 @@
+ /*
+
+ 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 "midisyncgroup_impl.h"
+#include "audiosync_impl.h"
+#include "midiclient_impl.h"
+#include "midimanager_impl.h"
+#include "timestampmath.h"
+
+using namespace Arts;
+using namespace std;
+
+MidiSyncGroup_impl::MidiSyncGroup_impl(MidiManager_impl *manager)
+ : manager(manager)
+{
+}
+
+MidiSyncGroup_impl::~MidiSyncGroup_impl()
+{
+ /* tell clients we're dead */
+ list<MidiClient_impl *>::iterator i;
+ for(i = clients.begin(); i != clients.end(); i++)
+ (*i)->setSyncGroup(0);
+
+ list<AudioSync_impl *>::iterator ai;
+ for(ai = audioSyncs.begin(); ai != audioSyncs.end(); ai++)
+ (*ai)->setSyncGroup(0);
+
+ manager->removeSyncGroup(this);
+}
+
+void MidiSyncGroup_impl::addClient(MidiClient client)
+{
+ /* add client to list */
+ MidiClient_impl *impl = manager->findClient(client.info().ID);
+ impl->setSyncGroup(this);
+ clients.push_back(impl);
+
+ impl->synchronizeTo(masterTimer.time());
+}
+
+void MidiSyncGroup_impl::removeClient(MidiClient client)
+{
+ /* remove client from the list */
+ MidiClient_impl *impl = manager->findClient(client.info().ID);
+ impl->setSyncGroup(0);
+ clients.remove(impl);
+}
+
+void MidiSyncGroup_impl::addAudioSync(AudioSync audioSync)
+{
+ AudioSync_impl *impl = AudioSync_impl::find(audioSync);
+ impl->setSyncGroup(this);
+ audioSyncs.push_back(impl);
+
+ impl->synchronizeTo(masterTimer.time());
+}
+
+void MidiSyncGroup_impl::removeAudioSync(AudioSync audioSync)
+{
+ AudioSync_impl *impl = AudioSync_impl::find(audioSync);
+ impl->setSyncGroup(0);
+ audioSyncs.remove(impl);
+}
+
+void MidiSyncGroup_impl::clientChanged(MidiClient_impl *client)
+{
+ client->synchronizeTo(masterTimer.time());
+}
+
+void MidiSyncGroup_impl::clientDied(MidiClient_impl *client)
+{
+ clients.remove(client);
+}
+
+void MidiSyncGroup_impl::audioSyncDied(AudioSync_impl *audioSync)
+{
+ audioSyncs.remove(audioSync);
+}
+
+TimeStamp MidiSyncGroup_impl::time()
+{
+ TimeStamp result = masterTimer.time();
+
+ list<MidiClient_impl *>::iterator i;
+ for(i = clients.begin(); i != clients.end(); i++)
+ result = timeStampMax(result, (*i)->clientTime());
+
+ list<AudioSync_impl *>::iterator ai;
+ for(ai = audioSyncs.begin(); ai != audioSyncs.end(); ai++)
+ result = timeStampMax(result, (*ai)->clientTime());
+
+ return result;
+}
+
+TimeStamp MidiSyncGroup_impl::playTime()
+{
+ return masterTimer.time();
+}
+
+void MidiSyncGroup_impl::adjustSync()
+{
+ list<AudioSync_impl *>::iterator ai;
+ for(ai = audioSyncs.begin(); ai != audioSyncs.end(); ai++)
+ (*ai)->synchronizeTo(masterTimer.time());
+}
diff --git a/arts/midi/midisyncgroup_impl.h b/arts/midi/midisyncgroup_impl.h
new file mode 100644
index 00000000..2c2191ac
--- /dev/null
+++ b/arts/midi/midisyncgroup_impl.h
@@ -0,0 +1,67 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef ARTS_MIDISYNCGROUP_IMPL_H
+#define ARTS_MIDISYNCGROUP_IMPL_H
+
+#include "artsmidi.h"
+
+namespace Arts {
+
+class MidiClient_impl;
+class MidiManager_impl;
+class AudioSync_impl;
+
+class MidiSyncGroup_impl : virtual public MidiSyncGroup_skel {
+protected:
+ SystemMidiTimer masterTimer;
+
+ MidiManager_impl *manager;
+ std::list<MidiClient_impl *> clients;
+ std::list<AudioSync_impl *> audioSyncs;
+
+public:
+ MidiSyncGroup_impl(MidiManager_impl *manager);
+ ~MidiSyncGroup_impl();
+
+ // public interface
+ void addClient(MidiClient client);
+ void removeClient(MidiClient client);
+
+ void addAudioSync(AudioSync audioSync);
+ void removeAudioSync(AudioSync audioSync);
+
+ // interface to MidiClient (AudioSync)
+ void clientChanged(MidiClient_impl *client);
+ void clientDied(MidiClient_impl *client);
+ void audioSyncDied(AudioSync_impl *audioSync);
+
+ TimeStamp time();
+ TimeStamp playTime();
+
+ // interface to MidiManager
+ void adjustSync();
+};
+
+}
+
+#endif /* ARTS_MIDISYNCGROUP_IMPL_H */
diff --git a/arts/midi/midisynctest.cc b/arts/midi/midisynctest.cc
new file mode 100644
index 00000000..4faa5279
--- /dev/null
+++ b/arts/midi/midisynctest.cc
@@ -0,0 +1,137 @@
+ /*
+
+ 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 "config.h"
+#include "artsmidi.h"
+#include "soundserver.h"
+#include "timestampmath.h"
+#include "debug.h"
+#include <stdio.h>
+#include <math.h>
+
+using namespace Arts;
+using namespace std;
+
+int main()
+{
+ Dispatcher dispatcher;
+
+ MidiManager midiManager = DynamicCast(Reference("global:Arts_MidiManager"));
+ if(midiManager.isNull())
+ arts_fatal("midimanager is null");
+
+ SoundServer soundServer = DynamicCast(Reference("global:Arts_SoundServer"));
+ if(soundServer.isNull())
+ arts_fatal("soundServer is null");
+
+ MidiSyncGroup syncGroup = midiManager.addSyncGroup();
+ MidiClient client = midiManager.addClient(mcdPlay, mctApplication, "midisynctest", "midisynctest");
+ syncGroup.addClient(client);
+
+ MidiPort port = client.addOutputPort();
+
+ MidiClient client2 = midiManager.addClient(mcdPlay, mctApplication, "midisynctest2", "midisynctest2");
+
+ syncGroup.addClient(client2);
+
+ MidiPort port2 = client2.addOutputPort();
+
+ /* setup audio synchronization */
+ AudioSync audioSync;
+ audioSync = DynamicCast(soundServer.createObject("Arts::AudioSync"));
+ if(audioSync.isNull())
+ arts_fatal("audioSync is null");
+
+ syncGroup.addAudioSync(audioSync);
+
+ const int C = 60;
+ const int D = 62;
+ const int E = 64;
+ const int F = 65, f = F - 12;
+ const int G = 67, g = G - 12;
+ const int A = 69, a = A - 12;
+ const int H = 71, h = H - 12;
+ int np = 0;
+ int notes[] = { C,E,G,E,a,C,E,C,f,a,C,a,g,h,D,h,0 };
+
+ printf("connect port1 and port2 to two different ports in the artscontrol midi manager,\n"
+ "hit return");
+ getchar();
+
+ TimeStamp t = port.time();
+ timeStampInc(t,TimeStamp(0,100000));
+ for(;;)
+ {
+ Synth_PLAY_WAV wav;
+ Synth_AMAN_PLAY sap;
+
+ MidiEvent e;
+
+ e = MidiEvent(t,MidiCommand(mcsNoteOn|0, notes[np], 100));
+
+ port.processEvent(e);
+ port2.processEvent(e);
+
+ if((np & 1) == 0)
+ {
+ /* setup wave player */
+ wav = DynamicCast(soundServer.createObject("Arts::Synth_PLAY_WAV"));
+ if(wav.isNull())
+ arts_fatal("can't create Arts::Synth_PLAY_WAV");
+
+ sap = DynamicCast(soundServer.createObject("Arts::Synth_AMAN_PLAY"));
+ if(sap.isNull())
+ arts_fatal("can't create Arts::Synth_AMAN_PLAY");
+
+ wav.filename("/opt/kde3/share/sounds/pop.wav");
+ sap.title("midisynctest2");
+ sap.autoRestoreID("midisynctest2");
+ connect(wav,sap);
+
+ audioSync.queueStart(wav);
+ audioSync.queueStart(sap);
+ audioSync.executeAt(t);
+ }
+
+ timeStampInc(t,TimeStamp(0,100000));
+
+ e = MidiEvent(t,MidiCommand(mcsNoteOff|0, notes[np], 100));
+
+ port.processEvent(e);
+ port2.processEvent(e);
+
+ if((np & 1) == 0)
+ {
+ audioSync.queueStop(wav);
+ audioSync.queueStop(sap);
+ audioSync.executeAt(t);
+ }
+
+ timeStampInc(t,TimeStamp(0,400000));
+
+ while(port.time().sec < (t.sec - 2))
+ usleep(100000);
+
+ np++;
+ if(notes[np] == 0) np = 0;
+ }
+}
diff --git a/arts/midi/miditest_impl.cc b/arts/midi/miditest_impl.cc
new file mode 100644
index 00000000..fe61e4c7
--- /dev/null
+++ b/arts/midi/miditest_impl.cc
@@ -0,0 +1,57 @@
+ /*
+
+ 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 "midimanager_impl.h"
+#include <stdio.h>
+
+namespace Arts {
+
+class MidiTest_impl : virtual public MidiTest_skel {
+public:
+ Arts::TimeStamp time()
+ {
+ return TimeStamp(0,0);
+ }
+ Arts::TimeStamp playTime()
+ {
+ return time();
+ }
+ void processCommand(const MidiCommand& command)
+ {
+ if((command.status & mcsCommandMask) == mcsNoteOn)
+ {
+ mcopbyte ch = command.status & mcsChannelMask;
+
+ printf("noteon ch = %d, note = %d, vel = %d\n",
+ ch,command.data1,command.data2);
+ }
+ }
+ void processEvent(const MidiEvent& event)
+ {
+ printf("At %ld.%06ld: ",event.time.sec,event.time.usec);
+ processCommand(event.command);
+ }
+};
+
+REGISTER_IMPLEMENTATION(MidiTest_impl);
+}
+
diff --git a/arts/midi/miditimercommon.cc b/arts/midi/miditimercommon.cc
new file mode 100644
index 00000000..205b72e5
--- /dev/null
+++ b/arts/midi/miditimercommon.cc
@@ -0,0 +1,72 @@
+ /*
+
+ 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 "artsmidi.h"
+#include "debug.h"
+#include "miditimercommon.h"
+#include "math.h"
+
+#undef DEBUG_JITTER
+
+using namespace std;
+using namespace Arts;
+
+MidiTimerCommon::MidiTimerCommon() :refCount(0)
+{
+ refCount = 0;
+}
+
+MidiTimerCommon::~MidiTimerCommon()
+{
+ arts_assert(refCount == 0);
+}
+
+void MidiTimerCommon::processQueue()
+{
+ TimeStamp now = time();
+
+ list<TSNote>::iterator n = noteQueue.begin();
+ while(n != noteQueue.end())
+ {
+ TSNote& note = *n;
+ TimeStamp& noteTime = note.event.time;
+
+ if( now.sec > noteTime.sec
+ || ((now.sec == noteTime.sec) && (now.usec > noteTime.usec)))
+ {
+#ifdef DEBUG_JITTER
+ float jitter = (now.sec-noteTime.sec) * 1000.0;
+ jitter += (float)(now.usec-noteTime.usec) / 1000.0;
+ arts_debug("midi jitter: %f",jitter);
+#endif
+
+ note.port.processCommand(note.event.command);
+ n = noteQueue.erase(n);
+ }
+ else n++;
+ }
+}
+
+void MidiTimerCommon::queueEvent(MidiPort port,const MidiEvent& event)
+{
+ noteQueue.push_back(TSNote(port, event));
+}
diff --git a/arts/midi/miditimercommon.h b/arts/midi/miditimercommon.h
new file mode 100644
index 00000000..5f4bb250
--- /dev/null
+++ b/arts/midi/miditimercommon.h
@@ -0,0 +1,59 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef ARTS_MIDI_MIDITIMERCOMMON_H
+#define ARTS_MIDI_MIDITIMERCOMMON_H
+
+#include "artsmidi.h"
+
+namespace Arts {
+
+class MidiTimerCommon {
+protected:
+ struct TSNote {
+ MidiPort port;
+ MidiEvent event;
+
+ TSNote() { /* for some stl impls */ }
+
+ TSNote(MidiPort port, const MidiEvent& event) :
+ port(port), event(event)
+ {
+ }
+ };
+ std::list<TSNote> noteQueue;
+
+ int refCount;
+ void processQueue();
+
+ MidiTimerCommon();
+ virtual ~MidiTimerCommon();
+
+public:
+ void unsubscribe() { if(--refCount == 0) delete this; }
+
+ void queueEvent(MidiPort port, const MidiEvent& event);
+ virtual TimeStamp time() = 0;
+};
+
+}
+#endif /* ARTS_MIDI_MIDITIMERCOMMON_H */
diff --git a/arts/midi/rawmidiport_impl.cc b/arts/midi/rawmidiport_impl.cc
new file mode 100644
index 00000000..0c9fd340
--- /dev/null
+++ b/arts/midi/rawmidiport_impl.cc
@@ -0,0 +1,306 @@
+ /*
+
+ 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 "artsmidi.h"
+#include <iomanager.h>
+#include <debug.h>
+#include <fcntl.h>
+
+using namespace std;
+
+namespace Arts {
+
+class RawMidiPort_impl : virtual public RawMidiPort_skel,
+ virtual public IONotify
+{
+protected:
+ int fd;
+
+ string _device;
+ bool _input, _output;
+ bool _running;
+ mcopbyte laststatus;
+ queue<mcopbyte> inq;
+ MidiClient clientRecord, clientPlay;
+ MidiPort outputPort;
+ MidiManager manager;
+
+ RawMidiPort self() {
+ return RawMidiPort::_from_base(_copy());
+ }
+ SystemMidiTimer timer;
+
+public:
+ RawMidiPort_impl()
+ :_device("/dev/midi"), _input(true), _output(true), _running(false),
+ clientRecord(MidiClient::null()), clientPlay(MidiClient::null()),
+ outputPort(MidiPort::null()),
+ manager(Reference("global:Arts_MidiManager"))
+ {
+ }
+ Arts::TimeStamp time()
+ {
+ return timer.time();
+ }
+ Arts::TimeStamp playTime()
+ {
+ return timer.time();
+ }
+
+ // attribute string running;
+ bool running() { return _running; }
+ void running(bool newrunning) {
+ if(_running == newrunning) return;
+
+ if(newrunning)
+ open();
+ else
+ close();
+
+ running_changed(_running);
+ }
+
+ // attribute string device;
+ void device(const string& newdevice)
+ {
+ if(newdevice == _device) return;
+
+ if(_running)
+ {
+ close();
+ _device = newdevice;
+ open();
+ }
+ else _device = newdevice;
+
+ device_changed(newdevice);
+ }
+ string device() { return _device; }
+
+ // attribute boolean input;
+ void input(bool newinput)
+ {
+ if(newinput == _input) return;
+
+ if(_running)
+ {
+ close();
+ _input = newinput;
+ open();
+ }
+ else _input = newinput;
+
+ input_changed(newinput);
+ }
+ bool input() { return _input; }
+
+ // attribute boolean output;
+ void output(bool newoutput)
+ {
+ if(newoutput == _output) return;
+
+ if(_running)
+ {
+ close();
+ _output = newoutput;
+ open();
+ }
+ else _output = newoutput;
+
+ output_changed(newoutput);
+ }
+ bool output() { return _output; }
+
+ bool open() {
+ arts_return_val_if_fail(_running == false, true);
+ arts_return_val_if_fail(_output || _input, false);
+ arts_return_val_if_fail(manager.isNull() == false, false);
+ laststatus = 0;
+
+ int mode = O_NDELAY;
+ if(_input)
+ {
+ if(_output)
+ mode |= O_RDWR;
+ else
+ mode |= O_RDONLY;
+ }
+ else mode |= O_WRONLY;
+
+ fd = ::open(_device.c_str(),mode);
+ if(fd != -1)
+ {
+ IOManager *iom = Dispatcher::the()->ioManager();
+ if(_output)
+ iom->watchFD(fd,IOType::read,this);
+
+ string name = "OSS Midi Port ("+_device+")";
+ if(_input)
+ {
+ clientRecord =
+ manager.addClient(mcdRecord,mctDestination,name,name);
+ clientRecord.addInputPort(self());
+ }
+ if(_output)
+ {
+ clientPlay =
+ manager.addClient(mcdPlay,mctDestination,name,name);
+ outputPort = clientPlay.addOutputPort();
+ }
+
+ _running = true;
+ running_changed(true);
+ }
+ return _running;
+ }
+
+ void close()
+ {
+ arts_return_if_fail(_running == true);
+
+ if(_input)
+ {
+ clientRecord.removePort(self());
+ clientRecord = MidiClient::null();
+ }
+ if(_output)
+ {
+ clientPlay.removePort(outputPort);
+ clientPlay = MidiClient::null();
+ }
+
+ Dispatcher::the()->ioManager()->remove(this,IOType::all);
+ ::close(fd);
+ }
+
+ int midiMsgLen(mcopbyte status)
+ {
+ switch(status & mcsCommandMask)
+ {
+ case mcsNoteOn:
+ case mcsNoteOff:
+ case mcsKeyPressure:
+ case mcsParameter:
+ case mcsPitchWheel:
+ return 3;
+ break;
+ case mcsProgram:
+ case mcsChannelPressure:
+ return 2;
+ break;
+ }
+ return 0;
+ }
+ void notifyIO(int fd, int type)
+ {
+ arts_return_if_fail(_running);
+ assert(fd == this->fd);
+
+ // convert iomanager notification types to audiosubsys notification
+ if(type & IOType::read)
+ {
+ mcopbyte buffer[1024];
+ int count = read(fd,buffer,1024);
+ for(int i=0; i<count; i++)
+ {
+ /*
+ * for now ignore all realtime-messages (0xF8 .. 0xFF),
+ * which may get * embedded *inside* every other message
+ */
+ if(buffer[i] < 0xf8)
+ inq.push(buffer[i]);
+ }
+ }
+ processMidi();
+ }
+
+ void processMidi()
+ {
+ for(;;)
+ {
+ // if we get a status byte, this is our new status
+ if(!inq.empty())
+ {
+ if(inq.front() & 0x80)
+ {
+ laststatus = inq.front();
+ inq.pop();
+ }
+ }
+
+ // try to read a midi message with our current status
+ // (this supports running status as well as normal messages)
+ int len = midiMsgLen(laststatus);
+ if(len)
+ {
+ if(len == 2)
+ {
+ if(inq.empty()) return; // need more input
+
+ MidiCommand command;
+ command.status = laststatus;
+ command.data1 = inq.front(); inq.pop();
+ command.data2 = 0;
+ outputPort.processCommand(command);
+ }
+ else if(len == 3)
+ {
+ if(inq.size() < 2) return; // need more input
+
+ MidiCommand command;
+ command.status = laststatus;
+ command.data1 = inq.front(); inq.pop();
+ command.data2 = inq.front(); inq.pop();
+ outputPort.processCommand(command);
+ }
+ else
+ {
+ arts_assert(false);
+ }
+ }
+ else
+ {
+ if(inq.empty()) return; // need more input
+
+ /* we are somewhat out of sync it seems -> read something
+ * away and hope we'll find a status byte */
+ inq.pop();
+ }
+ }
+ }
+ void processCommand(const MidiCommand& command)
+ {
+ char message[3] = { command.status, command.data1, command.data2 };
+
+ int len = midiMsgLen(command.status);
+ if(midiMsgLen(command.status))
+ write(fd, message, len);
+ }
+ void processEvent(const MidiEvent& event)
+ {
+ timer.queueEvent(self(), event);
+ }
+};
+
+REGISTER_IMPLEMENTATION(RawMidiPort_impl);
+}
+
diff --git a/arts/midi/systemmiditimer_impl.cc b/arts/midi/systemmiditimer_impl.cc
new file mode 100644
index 00000000..bda27a8c
--- /dev/null
+++ b/arts/midi/systemmiditimer_impl.cc
@@ -0,0 +1,105 @@
+ /*
+
+ 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 "artsmidi.h"
+#include "debug.h"
+#include "miditimercommon.h"
+
+using namespace std;
+using namespace Arts;
+
+namespace Arts {
+
+class SystemMidiTimerCommon : public MidiTimerCommon,
+ public TimeNotify {
+protected:
+ SystemMidiTimerCommon();
+ virtual ~SystemMidiTimerCommon();
+
+public:
+ // allocation: share one SystemMidiTimerCommon for everbody who needs one
+ static SystemMidiTimerCommon *subscribe();
+
+ void notifyTime();
+ TimeStamp time();
+};
+
+}
+
+static SystemMidiTimerCommon *SystemMidiTimerCommon_the = 0;
+
+SystemMidiTimerCommon::SystemMidiTimerCommon()
+{
+ SystemMidiTimerCommon_the = this;
+ Dispatcher::the()->ioManager()->addTimer(10, this);
+}
+
+SystemMidiTimerCommon::~SystemMidiTimerCommon()
+{
+ Dispatcher::the()->ioManager()->removeTimer(this);
+ SystemMidiTimerCommon_the = 0;
+}
+
+TimeStamp SystemMidiTimerCommon::time()
+{
+ timeval tv;
+ gettimeofday(&tv,0);
+ return TimeStamp(tv.tv_sec, tv.tv_usec);
+}
+
+void SystemMidiTimerCommon::notifyTime()
+{
+ processQueue();
+}
+
+SystemMidiTimerCommon *SystemMidiTimerCommon::subscribe()
+{
+ if(!SystemMidiTimerCommon_the) new SystemMidiTimerCommon();
+ SystemMidiTimerCommon_the->refCount++;
+ return SystemMidiTimerCommon_the;
+}
+
+class SystemMidiTimer_impl : public SystemMidiTimer_skel {
+protected:
+ SystemMidiTimerCommon *timer;
+public:
+ SystemMidiTimer_impl()
+ {
+ timer = SystemMidiTimerCommon::subscribe();
+ }
+ ~SystemMidiTimer_impl()
+ {
+ timer->unsubscribe();
+ }
+ TimeStamp time()
+ {
+ return timer->time();
+ }
+ void queueEvent(MidiPort port, const MidiEvent& event)
+ {
+ timer->queueEvent(port, event);
+ }
+};
+
+namespace Arts {
+ REGISTER_IMPLEMENTATION(SystemMidiTimer_impl);
+}
diff --git a/arts/midi/timestampmath.cc b/arts/midi/timestampmath.cc
new file mode 100644
index 00000000..ff33c280
--- /dev/null
+++ b/arts/midi/timestampmath.cc
@@ -0,0 +1,112 @@
+ /*
+
+ 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 "timestampmath.h"
+#include <arts/debug.h>
+#include <stdio.h>
+
+using namespace std;
+
+namespace Arts {
+void timeStampInc(TimeStamp& t, const TimeStamp& delta)
+{
+ /* expect a normalized t, delta */
+ arts_return_if_fail(t.usec >= 0 && t.usec < 1000000);
+ arts_return_if_fail(delta.usec >= 0 && delta.usec < 1000000);
+
+ t.sec += delta.sec;
+ t.usec += delta.usec;
+
+ if (t.usec >= 1000000)
+ {
+ t.usec -= 1000000;
+ t.sec += 1;
+ }
+
+ arts_assert (t.usec >= 0 && t.usec < 1000000);
+}
+
+void timeStampDec(TimeStamp& t, const TimeStamp& delta)
+{
+ /* expect a normalized t, delta */
+ arts_return_if_fail(t.usec >= 0 && t.usec < 1000000);
+ arts_return_if_fail(delta.usec >= 0 && delta.usec < 1000000);
+
+ t.sec -= delta.sec;
+ t.usec -= delta.usec;
+
+ if(t.usec < 0)
+ {
+ t.usec += 1000000;
+ t.sec -= 1;
+ }
+
+ arts_assert(t.usec >= 0 && t.usec < 1000000);
+}
+
+string timeStampToString(const TimeStamp& t)
+{
+ arts_return_val_if_fail(t.usec >= 0 && t.usec < 1000000, "");
+
+ char buffer[1024];
+ if(t.sec < 0 && t.usec != 0)
+ {
+ sprintf(buffer, "-%d.%06d", -t.sec-1, 1000000-t.usec);
+ }
+ else
+ {
+ sprintf(buffer, "%d.%06d", t.sec, t.usec);
+ }
+ return buffer;
+}
+
+double timeStampToDouble(const TimeStamp& t)
+{
+ arts_return_val_if_fail(t.usec >= 0 && t.usec < 1000000, 0.0);
+
+ return double(t.sec) + double(t.usec)/1000000.0;
+}
+
+TimeStamp timeStampFromDouble(double d)
+{
+ TimeStamp t;
+
+ arts_return_val_if_fail(d >= 0, t);
+
+ t.sec = int(d);
+ d -= t.sec;
+ t.usec = int(d * 1000000.0);
+
+ return t;
+}
+
+TimeStamp timeStampMax(const TimeStamp& t1, const TimeStamp& t2)
+{
+ if(t1.sec > t2.sec)
+ return t1;
+ else if((t1.sec == t2.sec) && (t1.usec > t2.usec))
+ return t1;
+ else
+ return t2;
+}
+
+}
diff --git a/arts/midi/timestampmath.h b/arts/midi/timestampmath.h
new file mode 100644
index 00000000..934df716
--- /dev/null
+++ b/arts/midi/timestampmath.h
@@ -0,0 +1,62 @@
+ /*
+
+ 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.
+
+ */
+
+#ifndef ARTS_TIMESTAMPMATH_H
+#define ARTS_TIMESTAMPMATH_H
+
+#include "artsmidi.h"
+#include <kdelibs_export.h>
+namespace Arts {
+
+/**
+ * increments the timestamp by delta
+ */
+KDE_EXPORT void timeStampInc(TimeStamp& t, const TimeStamp& delta);
+
+/**
+ * decrements the timestamp by delta
+ */
+void timeStampDec(TimeStamp& t, const TimeStamp& delta);
+
+/**
+ * stringifies a timestamp
+ */
+std::string timeStampToString(const TimeStamp& t);
+
+/**
+ * converts a timestamp to a double of seconds
+ */
+double timeStampToDouble(const TimeStamp& t);
+
+/**
+ * converts a double of seconds to a timestamp
+ */
+TimeStamp timeStampFromDouble(double d);
+
+/**
+ * returns the maximum of two timestamps
+ */
+TimeStamp timeStampMax(const TimeStamp& t1, const TimeStamp& t2);
+
+}
+
+#endif /* ARTS_TIMESTAMPMATH_H */
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);
diff --git a/arts/runtime/ArtsBuilderLoader.mcopclass b/arts/runtime/ArtsBuilderLoader.mcopclass
new file mode 100644
index 00000000..cceb4765
--- /dev/null
+++ b/arts/runtime/ArtsBuilderLoader.mcopclass
@@ -0,0 +1,4 @@
+Interface=Arts::ArtsBuilderLoader,Arts::Loader,Arts::Object
+LoadLanguage=aRts
+Language=C++
+Library=libartsbuilder.la
diff --git a/arts/runtime/LocalFactory.mcopclass b/arts/runtime/LocalFactory.mcopclass
new file mode 100644
index 00000000..e35f778b
--- /dev/null
+++ b/arts/runtime/LocalFactory.mcopclass
@@ -0,0 +1,3 @@
+Interface=Arts::LocalFactory,Arts::ObjectFactory,Arts::Object
+Language=C++
+Library=libartsbuilder.la
diff --git a/arts/runtime/Makefile.am b/arts/runtime/Makefile.am
new file mode 100644
index 00000000..b10abe7a
--- /dev/null
+++ b/arts/runtime/Makefile.am
@@ -0,0 +1,38 @@
+####### Runtime part of artsbuilder: this part will get dynamically loaded
+# into the aRts server (or other apps) to create structures which are designed
+# in artsbuilder. So to speak it's the "loader for the .arts language".
+
+AM_CXXFLAGS = -DEXAMPLES_DIR='"$(arts_datadir)/artsbuilder/examples"'
+INCLUDES= -I$(arts_includes) $(all_includes)
+
+lib_LTLIBRARIES = libartsbuilder.la
+
+libartsbuilder_la_SOURCES = artsbuilder.cc sequenceutils.cc \
+ structurebuilder_impl.cc structures_impl.cc moduleinfo.cc \
+ compatibility.cc localfactory_impl.cc artsbuilderloader_impl.cc
+
+libartsbuilder_la_LIBADD = -lmcop -lartsflow $(LIBDL)
+libartsbuilder_la_COMPILE_FIRST = artsbuilder.h
+libartsbuilder_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) \
+ -no-undefined
+
+artsbuilder.lo: artsbuilder.h
+artsbuilder.mcopclass: artsbuilder.h
+artsbuilder.mcoptype: artsbuilder.h
+artsbuilder.h artsbuilder.cc: $(srcdir)/artsbuilder.idl $(MCOPIDL)
+ $(MCOPIDL) -t -I$(arts_includes) $(srcdir)/artsbuilder.idl
+
+DISTCLEANFILES = artsbuilder.cc artsbuilder.h \
+ artsbuilder.mcoptype artsbuilder.mcopclass
+
+####### install idl files
+
+artsincludedir = $(includedir)/arts
+artsinclude_HEADERS = artsbuilder.h artsbuilder.idl
+
+mcopclassdir = $(libdir)/mcop/Arts
+mcopclass_DATA = StructureBuilder.mcopclass StructureDesc.mcopclass \
+ LocalFactory.mcopclass ArtsBuilderLoader.mcopclass
+
+mcoptypedir = $(libdir)/mcop
+mcoptype_DATA = artsbuilder.mcoptype artsbuilder.mcopclass
diff --git a/arts/runtime/StructureBuilder.mcopclass b/arts/runtime/StructureBuilder.mcopclass
new file mode 100644
index 00000000..5ea71358
--- /dev/null
+++ b/arts/runtime/StructureBuilder.mcopclass
@@ -0,0 +1,3 @@
+Interface=Arts::StructureBuilder,Arts::Object
+Language=C++
+Library=libartsbuilder.la
diff --git a/arts/runtime/StructureDesc.mcopclass b/arts/runtime/StructureDesc.mcopclass
new file mode 100644
index 00000000..3a7039e0
--- /dev/null
+++ b/arts/runtime/StructureDesc.mcopclass
@@ -0,0 +1,3 @@
+Interface=Arts::StructureDesc,Arts::Object
+Language=C++
+Library=libartsbuilder.la
diff --git a/arts/runtime/artsbuilder.idl b/arts/runtime/artsbuilder.idl
new file mode 100644
index 00000000..42ff393a
--- /dev/null
+++ b/arts/runtime/artsbuilder.idl
@@ -0,0 +1,228 @@
+/*
+ * DISCLAIMER: The interfaces in artsbuilder.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 <core.idl>
+#include <artsflow.idl>
+module Arts {
+ /*
+ * incoming or outgoing port?
+ */
+ enum PortDirection {input, output};
+
+ /**
+ * ConnType (maybe obsolete)
+ *
+ * ConnType: (connection type) this is wether this value is used
+ *
+ * - once (such as a filename of a waveplugin) -> property
+ * this implies that the allowed connection is only value
+ *
+ * - event based (such as midi events) -> event
+ * when events arrive, they are processed, when no events arrive,
+ * don't care
+ *
+ * - stream based (such as audio streams) -> stream
+ * every calculation of the module consumes/creates a sample
+ * that means: no data = no calculation possible
+ *
+ * WARNING: This is part of the artsbuilder dynamic programming interface
+ * as the MCOP port isn't there yet, this stuff may change
+ */
+ enum PortConnType { conn_stream, conn_event, conn_property};
+
+ /**
+ * PortType (maybe obsolete)
+ *
+ * isMultiPort specifies if the port can take multiple incoming
+ * connections or not. This is only relevant/allowed for input ports,
+ * the output of all output ports may be connected to any amount of
+ * receivers.
+ *
+ * Ports which can take multiple connections are handled differently
+ * internally. (Also, artsbuilder needs to know whether to allow multi-
+ * connections or not).
+ *
+ * WARNING: This is part of the artsbuilder dynamic programming interface
+ * as the MCOP port isn't there yet, this stuff may change
+ */
+ struct PortType {
+ PortDirection direction;
+ string dataType;
+ PortConnType connType;
+ boolean isMultiPort;
+ };
+
+ struct ModuleInfo {
+ string name;
+
+ //--- internal information:
+ // ports, first the input ports, then the output ports
+ sequence<PortType> ports;
+ sequence<string> portnames;
+ boolean isInterface;
+ boolean isStructure;
+ };
+
+ interface PortDesc;
+ interface ModuleDesc;
+ interface StructureDesc;
+ interface StructurePortDesc;
+
+ interface PortDesc {
+ // internal:
+ void constructor(ModuleDesc parent, string name, PortType type);
+
+ // ID is guaranteed to be unique in the structure the port belongs to
+ readonly attribute long ID;
+ readonly attribute ModuleDesc parent;
+
+ // Name is guaranteed to be unique for each module (no two in/out-
+ // ports with the same name allowed)
+ readonly attribute string name;
+ readonly attribute PortType type;
+
+ /*
+ * - for input channels, one of those must be true (only event
+ * channels may remain unconnected),
+ * - for output channels, only isConnected may be set
+ *
+ * only one of them may be set, not both
+ */
+ readonly attribute boolean isConnected;
+ attribute boolean hasValue; // set to false is only allowed writing
+
+ // connections, used when isConnected is true
+ readonly attribute sequence<PortDesc> connections;
+
+ // to be used as const value when hasValue is true
+ attribute float floatValue;
+ attribute string stringValue;
+
+ // the value as "any"
+ attribute Any value;
+
+ boolean connectTo(PortDesc port);
+ void disconnectFrom(PortDesc port);
+ void disconnectAll();
+
+ sequence<string> saveToList();
+ void loadFromList(sequence<string> list);
+
+ // never call this by hand, it will only be used by the module:
+ void internalConnectInput(PortDesc port);
+ void internalReConnect(sequence<PortDesc> allports);
+
+ readonly attribute long internalOldID;
+ };
+
+ interface ModuleDesc {
+ // internal
+ void constructor(StructureDesc parent, ModuleInfo info);
+
+ // ID is guaranteed to be unique in the structure the module belongs to
+ readonly attribute long ID;
+ readonly attribute StructureDesc parent;
+
+ readonly attribute string name;
+ readonly attribute sequence<PortDesc> ports;
+ readonly attribute long x, y, width, height;
+ readonly attribute boolean isInterface, isStructure;
+
+ boolean moveTo(long x, long y); // returns true when successful
+
+ PortDesc findPort(string name);
+ sequence<string> saveToList();
+ void loadFromList(sequence<string> list);
+ };
+
+ interface StructureDesc {
+ // internal:
+ long obtainID(); // only to be used as module or port
+
+ // public:
+ readonly attribute boolean valid;
+ attribute string name;
+ readonly attribute sequence<ModuleDesc> modules;
+ readonly attribute sequence<StructurePortDesc> ports;
+ readonly attribute sequence<string> inheritedInterfaces;
+
+ sequence<string> saveToList();
+ void loadFromList(sequence<string> list);
+
+ /**
+ * deletes all components in the structure
+ */
+ void clear();
+
+ ModuleDesc createModuleDesc(ModuleInfo info);
+ void freeModuleDesc(ModuleDesc moduledesc);
+
+ /**
+ * publishing (HMM)
+ */
+ readonly attribute ModuleInfo externalInterface;
+
+ // External Interface Ports:
+ StructurePortDesc createStructurePortDesc(PortType type,
+ string name);
+ void freeStructurePortDesc(StructurePortDesc portdesc);
+ void moveStructurePortDesc(StructurePortDesc portdesc,
+ long newposition);
+
+ // you will need to add the structure ports yourself
+ void addInheritedInterface(string iface);
+
+ // this will remove the associated structure ports
+ void removeInheritedInterface(string iface);
+ };
+
+ interface StructurePortDesc : PortDesc {
+ // internal
+ void constructor(StructureDesc parent, string name, PortType type);
+
+ // Position: how the port is positioned when the structure is used
+ // as module - 0 is leftmost, higher numbers are more right
+ readonly attribute long x, y, position;
+ readonly attribute StructureDesc parentStructure;
+
+ // if the port is associated with an inherited interface of the
+ // parent structure, then it should be setup here
+ attribute string inheritedInterface;
+
+ boolean moveTo(long x, long y); // returns true when successful
+
+ void lowerPosition(); // will move the port more left
+ void raisePosition(); // will move the port more right
+ void rename(string newname);
+
+ // only used by the structure to reorder the ports
+ void internalSetPosition(long position);
+ };
+
+ interface ObjectFactory {
+ object createObject(string name);
+ };
+
+ interface LocalFactory : ObjectFactory {
+ };
+
+ interface StructureBuilder {
+ void addFactory(ObjectFactory factory);
+ object createObject(StructureDesc structure);
+ ModuleDef createTypeInfo(StructureDesc structure);
+ };
+
+ interface ArtsBuilderLoader : Loader {
+ };
+
+ interface Structure : SynthModule {
+ void run();
+ void halt();
+ };
+};
diff --git a/arts/runtime/artsbuilderloader_impl.cc b/arts/runtime/artsbuilderloader_impl.cc
new file mode 100644
index 00000000..415106ef
--- /dev/null
+++ b/arts/runtime/artsbuilderloader_impl.cc
@@ -0,0 +1,285 @@
+ /*
+
+ 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 "artsbuilder.h"
+#include "debug.h"
+#include <stdlib.h>
+#include <fstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <set>
+#include <cstring>
+
+
+using namespace Arts;
+using namespace std;
+
+namespace Arts {
+
+class ArtsBuilderLoader_impl : virtual public ArtsBuilderLoader_skel {
+protected:
+ set<string> sourceDirs;
+
+ string lastDataVersion;
+ vector<TraderEntry> _traderEntries;
+ vector<ModuleDef> _modules;
+
+public:
+ Object loadObject(Arts::TraderOffer offer)
+ {
+ StructureDesc structureDesc;
+
+ vector<string> strseq;
+
+ // load file
+ vector<string> *filenames = offer.getProperty("File");
+ if(filenames->size() == 1)
+ {
+ string& filename = filenames->front();
+ arts_info("ArtsBuilderLoader: filename = %s", filename.c_str());
+
+ ifstream infile(filename.c_str());
+ string line;
+ while(getline(infile,line)) strseq.push_back(line);
+ }
+ delete filenames;
+
+ structureDesc.loadFromList(strseq);
+ if(structureDesc.name() != offer.interfaceName())
+ {
+ arts_warning("failed (name = %s).",structureDesc.name().c_str());
+ return Object::null();
+ }
+
+ StructureBuilder builder;
+ builder.addFactory(LocalFactory());
+
+ return builder.createObject(structureDesc);
+ }
+
+ vector<string> *listFiles(const string& pathname, const char *extension)
+ {
+ vector<string> *result = new vector<string>();
+
+ unsigned long extlen = strlen(extension);
+ DIR *dir = opendir(pathname.c_str());
+ if(dir != 0)
+ {
+ struct dirent *de;
+ while((de = readdir(dir)) != 0)
+ {
+ if(strlen(de->d_name) > extlen &&
+ strncmp(&de->d_name[strlen(de->d_name)-extlen],
+ extension,extlen) == 0)
+ result->push_back(de->d_name);
+ }
+ closedir(dir);
+ }
+ return result;
+ }
+
+ void collectInterfaces(const InterfaceDef& interface,
+ map<string, bool>& implemented)
+ {
+ if(!implemented[interface.name])
+ {
+ implemented[interface.name] = true;
+
+ vector<string>::const_iterator ii;
+ for(ii = interface.inheritedInterfaces.begin();
+ ii != interface.inheritedInterfaces.end(); ii++)
+ {
+ InterfaceDef id;
+ id = Dispatcher::the()->interfaceRepo().queryInterface(*ii);
+ collectInterfaces(id, implemented);
+ }
+ }
+ }
+
+ string getInterfacesList(const InterfaceDef& interface)
+ {
+ map<string, bool> implemented;
+ map<string, bool>::iterator ii;
+ string result;
+
+ collectInterfaces(interface, implemented);
+
+ for(ii = implemented.begin(); ii != implemented.end(); ii++)
+ result += ii->first + ",";
+ result += "Arts::Object";
+ return result;
+ }
+
+ void scanArtsFile(const string& filename)
+ {
+ StructureDesc structureDesc;
+ vector<string> strseq;
+
+ // load file
+ {
+ ifstream infile(filename.c_str());
+ string line;
+ int inmodule = 0;
+
+ while(getline(infile,line))
+ {
+ /*
+ * TODO - maybe there is a cleaner way?
+ *
+ * the following six lines are a bit hackish code to skip
+ * the module sections of the structures
+ *
+ * the problem with the module sections is this:
+ * we can't be sure that every module is known to the type
+ * system before we registered them with the type system,
+ * but as this code should be able to initially register .arts
+ * files with the type system, we can't rely that it has been
+ * done already (if we could, what would be the point of
+ * running this?)
+ */
+ if(strncmp(line.c_str(), "module=", 7) == 0)
+ inmodule = 1;
+
+ if(strncmp(line.c_str(), "{", 1) == 0 && inmodule == 1)
+ inmodule = 2;
+
+ if(strncmp(line.c_str(), "}", 1) == 0 && inmodule == 2)
+ inmodule = 0;
+
+ if(inmodule == 0)
+ strseq.push_back(line);
+ }
+ }
+
+ structureDesc.loadFromList(strseq);
+ string name = structureDesc.name();
+
+
+ arts_debug("%s [%s]\n",filename.c_str(),name.c_str());
+
+ /* add to _modules */
+ StructureBuilder builder;
+ ModuleDef md = builder.createTypeInfo(structureDesc);
+ _modules.push_back(md);
+
+ arts_assert(md.moduleName == name);
+ arts_assert(!md.interfaces.empty());
+
+ const InterfaceDef& id = md.interfaces.front();
+
+ /* add to _traderEntries */
+
+ TraderEntry entry;
+ entry.interfaceName = name;
+ entry.lines.push_back("Buildable=true");
+ entry.lines.push_back("Interface="+getInterfacesList(id));
+ entry.lines.push_back("Language=aRts");
+ entry.lines.push_back("File="+filename);
+
+ _traderEntries.push_back(entry);
+ /*
+ * TODO: more entries like
+ * Author="Stefan Westerfeld <stefan@space.twc.de>"
+ * URL="http://www.arts-project.org"
+ * License=...
+ */
+ }
+
+ void rescan()
+ {
+ lastDataVersion = dataVersion();
+
+ _traderEntries.clear();
+ _modules.clear();
+
+ set<string>::iterator si;
+ for(si = sourceDirs.begin(); si != sourceDirs.end(); si++)
+ {
+ vector<string> *files = listFiles(*si, ".arts");
+ vector<string>::iterator i;
+ for(i = files->begin(); i != files->end(); i++)
+ scanArtsFile(*si + "/" +*i);
+ delete files;
+ }
+ }
+
+ string dataVersion()
+ {
+ /*
+ * change this string if you change the loading algorithm to force
+ * rescanning even with the same data
+ */
+ string result = "ArtsBuilderLoader:1.1:";
+
+ bool first = true;
+
+ set<string>::iterator i;
+ for(i = sourceDirs.begin(); i != sourceDirs.end(); i++)
+ {
+ const string& filename = *i;
+
+ if(!first) result += ",";
+ first = false;
+
+ struct stat st;
+ if( stat(filename.c_str(), &st) == 0 )
+ {
+ char mtime[32];
+ sprintf(mtime,"[%ld]",st.st_mtime);
+ result += filename + mtime;
+ }
+ else
+ result += filename + "[-1]";
+ }
+ return result;
+ }
+
+ vector<TraderEntry> *traderEntries()
+ {
+ if(dataVersion() != lastDataVersion)
+ rescan();
+
+ return new vector<TraderEntry>(_traderEntries);
+ }
+
+ vector<ModuleDef> *modules()
+ {
+ if(dataVersion() != lastDataVersion)
+ rescan();
+
+ return new vector<ModuleDef>(_modules);
+ }
+
+ ArtsBuilderLoader_impl()
+ {
+ sourceDirs.insert(EXAMPLES_DIR);
+
+ const char *home = getenv("HOME");
+ if(home) sourceDirs.insert(home+string("/arts/structures"));
+ }
+};
+
+REGISTER_IMPLEMENTATION(ArtsBuilderLoader_impl);
+}
diff --git a/arts/runtime/compatibility.cc b/arts/runtime/compatibility.cc
new file mode 100644
index 00000000..190d471b
--- /dev/null
+++ b/arts/runtime/compatibility.cc
@@ -0,0 +1,56 @@
+ /*
+
+ Copyright (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 "compatibility.h"
+#include "debug.h"
+#include <iostream>
+
+#undef DEBUG_COMPATIBILITY
+
+using namespace std;
+
+string Arts::OldFormatTranslator::newModuleName(const string& module)
+{
+#ifdef DEBUG_COMPATIBILITY
+ arts_debug("COMPAT: %s", module.c_str());
+#endif
+
+ if(module.substr(0,10) == "Interface_") return "Arts::"+module;
+ if(module.substr(0,6) == "Synth_") return "Arts::"+module;
+ return module;
+}
+
+string Arts::OldFormatTranslator::newPortName(const string& module, const string& port)
+{
+#ifdef DEBUG_COMPATIBILITY
+ arts_debug("COMPAT: %s.%s", module.c_str(), port.c_str());
+#endif
+
+ if(module == "Arts::Synth_MUL") {
+ if(port == "invalue") return "invalue1";
+ if(port == "faktor") return "invalue2";
+ }
+ if(module == "Arts::Synth_ADD") {
+ if(port == "invalue") return "invalue1";
+ if(port == "addit") return "invalue2";
+ }
+ return port;
+}
diff --git a/arts/runtime/compatibility.h b/arts/runtime/compatibility.h
new file mode 100644
index 00000000..b95b0266
--- /dev/null
+++ b/arts/runtime/compatibility.h
@@ -0,0 +1,36 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef ARTS_COMPATIBILITY_H
+#define ARTS_COMPATIBILITY_H
+
+#include <string>
+
+namespace Arts {
+ class OldFormatTranslator {
+ public:
+ static std::string newModuleName(const std::string& module);
+ static std::string newPortName(const std::string& module,
+ const std::string& port);
+ };
+}
+
+#endif /* ARTS_COMPATIBILITY_H */
diff --git a/arts/runtime/localfactory_impl.cc b/arts/runtime/localfactory_impl.cc
new file mode 100644
index 00000000..bf55271c
--- /dev/null
+++ b/arts/runtime/localfactory_impl.cc
@@ -0,0 +1,15 @@
+#include "artsbuilder.h"
+
+using namespace Arts;
+using namespace std;
+
+class LocalFactory_impl : virtual public LocalFactory_skel {
+public:
+ Object createObject(const string& name)
+ {
+ return SubClass(name);
+ }
+};
+
+REGISTER_IMPLEMENTATION(LocalFactory_impl);
+
diff --git a/arts/runtime/moduleinfo.cc b/arts/runtime/moduleinfo.cc
new file mode 100644
index 00000000..28a44310
--- /dev/null
+++ b/arts/runtime/moduleinfo.cc
@@ -0,0 +1,106 @@
+ /*
+
+ Copyright (C) 2000 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.
+
+ Permission is also granted to link this program with the Qt
+ library, treating Qt like a library that normally accompanies the
+ operating system kernel, whether or not that is in fact the case.
+
+ */
+
+#include "moduleinfo.h"
+
+using namespace std;
+
+static void gatherPorts(Arts::InterfaceDef& idef, Arts::ModuleInfo& minfo,
+ map<string, bool>& done)
+{
+ Arts::InterfaceRepo interfaceRepo=Arts::Dispatcher::the()->interfaceRepo();
+
+ vector<string>::iterator ii = idef.inheritedInterfaces.begin();
+ while(ii != idef.inheritedInterfaces.end())
+ {
+ Arts::InterfaceDef inherited = interfaceRepo.queryInterface(*ii++);
+ gatherPorts(inherited,minfo,done);
+ }
+
+ if(idef.name == "Arts::Object" || idef.name == "Arts::SynthModule")
+ {
+ // don't gather members of these basic interfaces as ports
+ return;
+ }
+ vector<Arts::AttributeDef>::iterator i;
+ for(i=idef.attributes.begin(); i != idef.attributes.end(); i++)
+ {
+ // 1 = direction, 10000 = connectiontype
+ long complete = 0;
+ Arts::PortType ptype;
+
+ if(i->flags & Arts::streamIn)
+ {
+ ptype.direction = Arts::input;
+ complete += 1;
+ }
+ else if(i->flags & Arts::streamOut)
+ {
+ ptype.direction = Arts::output;
+ complete += 1;
+ }
+
+ ptype.dataType = i->type;
+
+ if(i->flags & Arts::attributeStream)
+ {
+ ptype.connType = Arts::conn_stream;
+ complete += 10000;
+ }
+ else if(i->flags & Arts::attributeAttribute)
+ {
+ ptype.connType = Arts::conn_property;
+ complete += 10000;
+ }
+
+ ptype.isMultiPort = (i->flags & Arts::streamMulti);
+
+ if(complete == 10001 && !done[i->name])
+ {
+ minfo.portnames.push_back(i->name);
+ minfo.ports.push_back(ptype);
+ done[i->name] = true;
+ }
+ }
+}
+
+Arts::ModuleInfo makeModuleInfo(const string& name)
+{
+ Arts::InterfaceRepo interfaceRepo=Arts::Dispatcher::the()->interfaceRepo();
+ Arts::InterfaceDef idef = interfaceRepo.queryInterface(name);
+ Arts::ModuleInfo minfo;
+
+ if(!idef.name.empty())
+ {
+ map<string,bool> done;
+ minfo.name = name;
+ minfo.isStructure = false;
+ minfo.isInterface = false;
+
+ gatherPorts(idef,minfo,done);
+ }
+ return minfo;
+}
+
diff --git a/arts/runtime/moduleinfo.h b/arts/runtime/moduleinfo.h
new file mode 100644
index 00000000..1067f342
--- /dev/null
+++ b/arts/runtime/moduleinfo.h
@@ -0,0 +1,33 @@
+ /*
+
+ Copyright (C) 2000 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.
+
+ Permission is also granted to link this program with the Qt
+ library, treating Qt like a library that normally accompanies the
+ operating system kernel, whether or not that is in fact the case.
+
+ */
+
+#ifndef MODULEINFO_H
+#define MODULEINFO_H
+
+#include "artsbuilder.h"
+#include <kdelibs_export.h>
+KDE_EXPORT Arts::ModuleInfo makeModuleInfo(const std::string& name);
+
+#endif /* MODULEINFO_H */
diff --git a/arts/runtime/sequenceutils.cc b/arts/runtime/sequenceutils.cc
new file mode 100644
index 00000000..9634f40b
--- /dev/null
+++ b/arts/runtime/sequenceutils.cc
@@ -0,0 +1,188 @@
+ /*
+
+ Copyright (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 "sequenceutils.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <config.h>
+
+using namespace std;
+
+#if 0
+void sqprintf(ArtsCorba::StringSeq *list, const char *fmt, ...)
+{
+ char p[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ (void) vsnprintf(p, 1024, fmt, ap);
+ va_end(ap);
+
+ unsigned long len = list->length();
+ list->length(len+1);
+ (*list)[len] = CORBA::string_dup(p);
+}
+#endif
+
+void sqprintf(vector<string> *list, const char *fmt, ...)
+{
+ char p[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ (void) vsnprintf(p, 1024, fmt, ap);
+ va_end(ap);
+
+ list->push_back(p);
+}
+
+int parse_line(const char *in, char *& cmd, char *& param)
+{
+ int i,cmdlen=0,paramlen=0;
+ static char static_cmd[1000], static_param[1000];
+
+ cmd = static_cmd;
+ param = static_param;
+ i = 0;
+
+ while(in[i] == ' ' || in[i] == '\t') i++;
+
+ if(in[i] == 0) return(0);
+
+ while(in[i] != '=' && in[i] != 0) cmd[cmdlen++] = in[i++];
+ if(in[i] != 0) i++;
+ while(in[i] != 0) param[paramlen++] = in[i++];
+
+ cmd[cmdlen] = 0;
+ param[paramlen] = 0;
+
+ if(paramlen) return(2);
+ if(cmdlen) return(1);
+ return(0);
+}
+
+int parse_line(const string& in, string& cmd, string& param)
+{
+ char *ccmd, *cparam;
+ int result = parse_line(in.c_str(),ccmd,cparam);
+ param = cparam;
+ cmd = ccmd;
+ return result;
+}
+
+#if 0
+void addSubStringSeq(ArtsCorba::StringSeq *target, ArtsCorba::StringSeq *source)
+{
+ unsigned long i;
+
+ sqprintf(target,"{");
+ for(i=0;i<source->length();i++)
+ {
+ unsigned long len = target->length();
+ target->length(len+1);
+ string srcstring = string(" ") + string((*source)[i]);
+ (*target)[len] = CORBA::string_dup(srcstring.c_str());
+ }
+ sqprintf(target,"}");
+}
+#endif
+
+void addSubStringSeq(vector<string> *target, const vector<string> *source)
+{
+ sqprintf(target,"{");
+
+ vector<string>::const_iterator i;
+ for(i=source->begin();i != source->end();i++)
+ target->push_back(" " + *i);
+
+ sqprintf(target,"}");
+}
+
+#if 0
+void appendStringSeq(ArtsCorba::StringSeq *target, ArtsCorba::StringSeq *source)
+{
+ unsigned long i;
+
+ for(i=0;i<source->length();i++)
+ {
+ unsigned long len = target->length();
+ target->length(len+1);
+ (*target)[len] = CORBA::string_dup((*source)[i]);
+ }
+}
+#endif
+
+void appendStringSeq(vector<string> *target, const vector<string> *source)
+{
+ vector<string>::const_iterator i;
+ for(i=source->begin();i != source->end();i++)
+ target->push_back(*i);
+}
+
+#if 0
+ArtsCorba::StringSeq *getSubStringSeq(const ArtsCorba::StringSeq *seq,unsigned long& i)
+{
+ ArtsCorba::StringSeq *result = new ArtsCorba::StringSeq;
+ char empty[1] = {0};
+ char *cmd = empty,*param;
+
+
+ while(strcmp(cmd,"{") && i<seq->length())
+ parse_line((*seq)[i++],cmd,param);
+
+ int brackets = 1;
+
+ while(i<seq->length())
+ {
+ parse_line((*seq)[i],cmd,param);
+ if(strcmp(cmd,"{") == 0) brackets++;
+ if(strcmp(cmd,"}") == 0) brackets--;
+ if(brackets == 0) return(result);
+
+ unsigned long len = result->length();
+ result->length(len+1);
+ (*result)[len] = CORBA::string_dup((*seq)[i]);
+ i++;
+ }
+ return(result);
+}
+#endif
+
+vector<string> *getSubStringSeq(const vector<string> *seq,unsigned long& i)
+{
+ vector<string> *result = new vector<string>;
+ string cmd = "",param;
+
+ while(cmd != "{" && i<seq->size())
+ parse_line((*seq)[i++],cmd,param);
+
+ int brackets = 1;
+
+ while(i<seq->size())
+ {
+ parse_line((*seq)[i],cmd,param);
+ if(cmd == "{") brackets++;
+ if(cmd == "}") brackets--;
+ if(brackets == 0) return(result);
+
+ result->push_back((*seq)[i]);
+ i++;
+ }
+ return result;
+}
diff --git a/arts/runtime/sequenceutils.h b/arts/runtime/sequenceutils.h
new file mode 100644
index 00000000..5925bff3
--- /dev/null
+++ b/arts/runtime/sequenceutils.h
@@ -0,0 +1,41 @@
+ /*
+
+ Copyright (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.
+
+ */
+
+#ifndef ARTS_SEQUENCEUTILS_H
+#define ARTS_SEQUENCEUTILS_H
+
+#include <vector>
+#include <string>
+#include <kdelibs_export.h>
+
+KDE_EXPORT int parse_line(const char *in, char *& cmd, char *& param);
+
+KDE_EXPORT void sqprintf(std::vector<std::string> *list, const char *fmt, ...)
+#ifdef __GNUC__
+ __attribute__ (( format (printf, 2, 3)))
+#endif
+;
+KDE_EXPORT void addSubStringSeq(std::vector<std::string> *target, const std::vector<std::string> *source);
+KDE_EXPORT void appendStringSeq(std::vector<std::string> *target, const std::vector<std::string> *source);
+KDE_EXPORT int parse_line(const std::string& in, std::string& cmd, std::string& param);
+KDE_EXPORT std::vector<std::string> *getSubStringSeq(const std::vector<std::string> *seq,unsigned long& i);
+
+#endif /* ARTS_SEQUENCEUTILS_H */
diff --git a/arts/runtime/structurebuilder_impl.cc b/arts/runtime/structurebuilder_impl.cc
new file mode 100644
index 00000000..63dd6927
--- /dev/null
+++ b/arts/runtime/structurebuilder_impl.cc
@@ -0,0 +1,347 @@
+ /*
+
+ Copyright (C) 2000,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 "artsbuilder.h"
+#include "artsflow.h"
+#include "connect.h"
+#include "debug.h"
+#include "flowsystem.h"
+#include "stdsynthmodule.h"
+#include "dynamicrequest.h"
+#include "dynamicskeleton.h"
+#include "startupmanager.h"
+#include <list>
+
+//#define STRUCTBUILDER_DEBUG 1
+
+using namespace Arts;
+using namespace std;
+
+class StructureBuilder_impl : virtual public StructureBuilder_skel {
+protected:
+ list<ObjectFactory> factories;
+public:
+ void addFactory(ObjectFactory factory);
+ Object createObject(StructureDesc structure);
+ ModuleDef createTypeInfo(StructureDesc structure);
+};
+
+REGISTER_IMPLEMENTATION(StructureBuilder_impl);
+
+typedef DynamicSkeleton<SynthModule_skel> SynthModule_dskel;
+
+class Structure_impl : virtual public SynthModule_dskel,
+ virtual public StdSynthModule {
+protected:
+ list<Object> structureObjects;
+
+ struct ForwardMethod {
+ string method;
+ Object destObject;
+ string destMethod;
+ };
+
+ list<ForwardMethod> forwardMethods;
+
+public:
+ Structure_impl(StructureDesc structure, list<ObjectFactory>& factories);
+ void streamInit();
+ void streamEnd();
+
+ void process(long methodID, Buffer *request, Buffer *result);
+};
+
+void StructureBuilder_impl::addFactory(ObjectFactory factory)
+{
+ factories.push_back(factory);
+}
+
+ModuleDef StructureBuilder_impl::createTypeInfo(StructureDesc structure)
+{
+ ModuleDef md;
+ InterfaceDef id;
+
+/* convert structure to InterfaceDef id */
+ md.moduleName = id.name = structure.name();
+ id.inheritedInterfaces.push_back("Arts::SynthModule");
+
+ vector<string> *otherInterfaces = structure.inheritedInterfaces();
+ vector<string>::iterator ii;
+ for(ii = otherInterfaces->begin(); ii != otherInterfaces->end(); ii++)
+ id.inheritedInterfaces.push_back(*ii);
+ delete otherInterfaces;
+
+ vector<StructurePortDesc> *ports = structure.ports();
+ vector<StructurePortDesc>::iterator pi;
+ for(pi = ports->begin(); pi != ports->end(); pi++)
+ {
+ const Arts::PortType& type = pi->type();
+
+ // if we inherited the port from a parent interface, we don't need to
+ // list it in our interface description
+ if(pi->inheritedInterface().empty())
+ {
+ AttributeDef ad;
+ ad.name = pi->name();
+
+ // This is a little tricky, as input ports (which are bringing data
+ // from outside into the structure) are saved as output ports (and
+ // output ports as input ports).
+ ad.flags = AttributeType(
+ ((type.direction == input)?streamOut:streamIn) |
+ ((type.connType == conn_stream)?attributeStream:attributeAttribute)
+ );
+ ad.type = type.dataType;
+
+ id.attributes.push_back(ad);
+ }
+ }
+ delete ports;
+
+ md.interfaces.push_back(id);
+
+ return md;
+}
+
+namespace Arts {
+static class StructureBuilderCleanUp : public StartupClass {
+public:
+ vector<long> types;
+ void startup() { };
+ void shutdown() {
+ vector<long>::iterator i;
+ for(i = types.begin(); i != types.end(); i++)
+ Dispatcher::the()->interfaceRepo().removeModule(*i);
+ types.clear();
+ }
+ virtual ~StructureBuilderCleanUp() {}
+} structureBuilderCleanUp;
+}
+
+Object StructureBuilder_impl::createObject(StructureDesc structure)
+{
+ ModuleDef md = createTypeInfo(structure);
+
+ // FIXME: find some faster way of ensuring type consistency than creating
+ // the thing from scratch every time
+ structureBuilderCleanUp.types.push_back(Dispatcher::the()->interfaceRepo().insertModule(md));
+ Object obj = Object::_from_base(new Structure_impl(structure, factories));
+ return obj;
+}
+
+Structure_impl::Structure_impl(StructureDesc structureDesc,
+ list<ObjectFactory>& factories)
+ : SynthModule_dskel(structureDesc.name())
+{
+ map<long, Object> moduleMap;
+ vector<ModuleDesc> *modules = structureDesc.modules();
+ vector<ModuleDesc>::iterator mi;
+
+ // create each object
+ for(mi = modules->begin(); mi != modules->end(); mi++)
+ {
+ ModuleDesc& md = *mi;
+
+#ifdef STRUCTBUILDER_DEBUG
+ cout << "create " << md.name() << endl;
+#endif
+ Object o = Object::null(); //SubClass(md.name());
+
+ Object_skel *skel = 0;
+ skel = ObjectManager::the()->create(md.name());
+ if(skel) o = Object::_from_base(skel);
+
+#ifdef STRUCTBUILDER_DEBUG
+ if(o.isNull()) cout << "no local creator for " << md.name() << endl;
+#endif
+ list<ObjectFactory>::iterator fi = factories.begin();
+ while(o.isNull() && fi != factories.end())
+ {
+ o = fi->createObject(md.name());
+ fi++;
+ }
+
+#ifdef STRUCTBUILDER_DEBUG
+ if(o.isNull()) cout << "no remote creator for " << md.name() << endl;
+#endif
+ assert(!o.isNull());
+ moduleMap[md.ID()] = o;
+ structureObjects.push_back(o);
+ }
+
+ // connect objects and set values
+ for(mi = modules->begin(); mi != modules->end(); mi++)
+ {
+ Object& object = moduleMap[mi->ID()];
+
+ vector<PortDesc> *ports = mi->ports();
+ vector<PortDesc>::iterator pi;
+
+ for(pi = ports->begin(); pi != ports->end(); pi++)
+ {
+ PortDesc& pd = *pi;
+ const Arts::PortType& ptype = pd.type();
+
+ if(pd.hasValue())
+ {
+ // set values
+#ifdef STRUCTBUILDER_DEBUG
+ cout << "value " << mi->name() << "." << pi->name() << endl;
+#endif
+
+ if(ptype.connType == conn_property)
+ {
+ DynamicRequest req(object);
+ req.method("_set_"+pi->name());
+ req.param(pd.value());
+
+ bool requestOk = req.invoke();
+ arts_assert(requestOk);
+ }
+ else
+ {
+ if(ptype.dataType == "float")
+ setValue(object,pi->name(),pd.floatValue());
+ else
+ arts_warning("unexpected property type %s",
+ ptype.dataType.c_str());
+ //setStringValue(object,pd.stringValue());
+ }
+ }
+ else if(pd.isConnected() && ptype.direction == output)
+ {
+ // create connections
+
+ vector<PortDesc> *connections = pd.connections();
+ vector<PortDesc>::iterator ci;
+
+ for(ci = connections->begin(); ci != connections->end(); ci++)
+ {
+ if(!ci->parent().isNull()) // structureport otherwise
+ {
+ Object& dest = moduleMap[ci->parent().ID()];
+#ifdef STRUCTBUILDER_DEBUG
+ cout << "connect " << mi->name() << "." << pi->name()
+ << " to " << ci->parent().name()
+ << "." << ci->name() << endl;
+#endif
+ connect(object,pd.name(),dest,ci->name());
+ }
+ }
+ delete connections;
+ }
+ }
+ delete ports;
+ }
+ delete modules;
+
+ // create ports (should be done via dynamic impl class...)
+
+ vector<StructurePortDesc> *ports = structureDesc.ports();
+ vector<StructurePortDesc>::iterator pi;
+
+ for(pi = ports->begin(); pi != ports->end(); pi++)
+ {
+ Arts::StructurePortDesc& pd = *pi;
+ if(pd.isConnected())
+ {
+ // create connections
+
+ vector<PortDesc> *connections = pd.connections();
+ vector<PortDesc>::iterator ci;
+
+ for(ci = connections->begin(); ci != connections->end(); ci++)
+ {
+ Object& dest = moduleMap[ci->parent().ID()];
+#ifdef STRUCTBUILDER_DEBUG
+ cout << "virtualize " << pi->name()
+ << " to " << ci->parent().name() << "." << ci->name()
+ << endl;
+#endif
+
+ _node()->virtualize(pd.name(),dest._node(),ci->name());
+
+ if(pd.type().connType == conn_property)
+ {
+ ForwardMethod fm;
+ fm.method = "_set_"+pd.name();
+ fm.destObject = dest;
+ fm.destMethod = "_set_"+ci->name();
+ forwardMethods.push_back(fm);
+ }
+ }
+ delete connections;
+ }
+ }
+ delete ports;
+}
+
+void Structure_impl::streamInit()
+{
+ list<Object>::iterator i;
+
+#ifdef STRUCTBUILDER_DEBUG
+ cout << "vstructure: got streamInit()" << endl;
+#endif
+
+ for(i=structureObjects.begin(); i != structureObjects.end(); i++)
+ {
+ if(i->_base()->_isCompatibleWith("Arts::SynthModule"))
+ i->_node()->start();
+ }
+}
+
+void Structure_impl::streamEnd()
+{
+ list<Object>::iterator i;
+
+#ifdef STRUCTBUILDER_DEBUG
+ cout << "vstructure: got streamEnd()" << endl;
+#endif
+
+ for(i=structureObjects.begin(); i != structureObjects.end(); i++)
+ if(i->_base()->_isCompatibleWith("Arts::SynthModule"))
+ i->_node()->stop();
+}
+
+void Structure_impl::process(long methodID, Buffer *request, Buffer *result)
+{
+ const MethodDef& methodDef = getMethodDef(methodID);
+
+ arts_debug("Structure_impl: got method, method ID=%ld name='%s'",
+ methodID, methodDef.name.c_str());
+
+ list<ForwardMethod>::iterator fi;
+ for(fi = forwardMethods.begin(); fi != forwardMethods.end(); fi++)
+ {
+ if(fi->method == methodDef.name)
+ {
+ Any a;
+ a.type = methodDef.signature[0].type;
+
+ while(request->remaining() > 0)
+ a.value.push_back(request->readByte());
+
+ DynamicRequest(fi->destObject).method(fi->destMethod).param(a).invoke();
+ }
+ }
+}
diff --git a/arts/runtime/structures_impl.cc b/arts/runtime/structures_impl.cc
new file mode 100644
index 00000000..7c5a5e05
--- /dev/null
+++ b/arts/runtime/structures_impl.cc
@@ -0,0 +1,1421 @@
+#include "artsbuilder.h"
+#include "weakreference.h"
+#include "moduleinfo.h"
+#include "compatibility.h"
+#include "sequenceutils.h"
+#include <stdio.h>
+#include <iostream>
+
+using namespace std;
+using namespace Arts;
+
+typedef WeakReference<PortDesc> PortDesc_wref;
+typedef WeakReference<ModuleDesc> ModuleDesc_wref;
+typedef WeakReference<StructureDesc> StructureDesc_wref;
+
+class PortDesc_impl :virtual public Arts::PortDesc_skel {
+protected:
+ string _name;
+ PortType _type;
+ vector<PortDesc_wref> _connections;
+ ModuleDesc_wref _parent;
+ bool _isConnected;
+ bool _hasValue;
+ Any _value;
+ long _ID;
+ long _oldID;
+ list<long> oldConnections;
+
+ void removeNullConnections();
+
+public:
+ ~PortDesc_impl();
+
+ inline PortDesc self() { return PortDesc::_from_base(_copy()); }
+ void constructor(ModuleDesc parent, const string& name, const PortType& type);
+
+ void disconnectAll();
+ long ID();
+ ModuleDesc parent();
+ string name();
+ PortType type();
+ bool isConnected();
+ bool hasValue();
+ void hasValue(bool newvalue);
+ vector<PortDesc> *connections();
+ float floatValue();
+ void floatValue( float _new_value );
+
+ string stringValue();
+ void stringValue( const string& _new_value );
+
+ Any value();
+ void value( const Any& _new_value );
+
+ bool connectTo( PortDesc port );
+ void internalConnectInput( PortDesc port );
+ void disconnectFrom( PortDesc port );
+
+ void loadFromList(const vector<string>& list);
+ vector<string> *saveToList();
+
+ void internalReConnect( const vector<PortDesc>& allports );
+ long internalOldID();
+};
+
+class ModuleDesc_impl : virtual public ModuleDesc_skel {
+private:
+ long _ID;
+ StructureDesc_wref _parent;
+ string _name;
+ long _x, _y;
+ vector<PortDesc> _ports;
+ long collectPorts( const Arts::ModuleInfo& info );
+
+ bool _isInterface, _isStructure;
+
+ inline ModuleDesc self() { return ModuleDesc::_from_base(_copy()); }
+
+public:
+ long ID();
+ StructureDesc parent();
+ string name();
+ vector<PortDesc> *ports();
+ long height();
+ long width();
+ long x();
+ long y();
+ bool moveTo( long x, long y );
+ void constructor( StructureDesc parent, const ModuleInfo& info );
+
+ void loadFromList(const vector<string>& list);
+ vector<string> *saveToList();
+
+ ~ModuleDesc_impl();
+
+ bool isInterface();
+ bool isStructure();
+ Arts::PortDesc findPort(const string& name);
+};
+
+class StructureDesc_impl : virtual public Arts::StructureDesc_skel {
+protected:
+ bool _valid;
+ vector<ModuleDesc> _modules;
+ vector<StructurePortDesc> _ports; /* only structure ports which are part of the interface */
+ vector<string> _inheritedInterfaces;
+ long nextID;
+ ModuleInfo _externalInterface;
+
+ inline StructureDesc self() { return StructureDesc::_from_base(_copy()); }
+public:
+ string name();
+ void name(const string& newName);
+
+ vector<string> *saveToList();
+ void loadFromList(const vector<string>& list);
+ vector<ModuleDesc> *modules();
+ vector<StructurePortDesc> *ports();
+ vector<string> *inheritedInterfaces();
+
+ void clear();
+ long obtainID();
+ long width();
+ long height();
+ bool valid();
+
+ ModuleDesc createModuleDesc( const ModuleInfo& info );
+ ModuleDesc createModuleDesc( const string& name );
+ void freeModuleDesc(ModuleDesc moduledesc);
+
+ // external interface
+ StructurePortDesc createStructurePortDesc(const PortType& type, const string& name);
+ void freeStructurePortDesc(StructurePortDesc portdesc);
+ void moveStructurePortDesc(StructurePortDesc portdesc, long newposition);
+
+ ModuleInfo externalInterface();
+
+ void addInheritedInterface(const string& iface);
+ void removeInheritedInterface(const string& iface);
+
+ StructureDesc_impl();
+ ~StructureDesc_impl();
+};
+
+class StructurePortDesc_impl :
+ virtual public PortDesc_impl,
+ virtual public StructurePortDesc_skel
+{
+protected:
+ StructureDesc_wref _parentStructure;
+ long _x, _y, _position;
+ string _inheritedInterface;
+
+ inline StructurePortDesc self() {
+ return StructurePortDesc::_from_base(_copy());
+ }
+public:
+ void constructor(StructureDesc parent, const string& name,
+ const PortType& type);
+ ~StructurePortDesc_impl();
+
+ long x();
+ long y();
+ long position();
+ void lowerPosition();
+ void raisePosition();
+ void rename(const string& newname);
+ string inheritedInterface();
+ void inheritedInterface(const string& iface);
+
+ void internalSetPosition(long position);
+ StructureDesc parentStructure();
+ bool moveTo( long X, long Y );
+
+ void loadFromList(const vector<string>& list);
+ vector<string> *saveToList();
+};
+
+REGISTER_IMPLEMENTATION(PortDesc_impl);
+REGISTER_IMPLEMENTATION(ModuleDesc_impl);
+REGISTER_IMPLEMENTATION(StructureDesc_impl);
+REGISTER_IMPLEMENTATION(StructurePortDesc_impl);
+
+/*
+#include "structures.h"
+*/
+#include "debug.h"
+#include <vector>
+#include <algorithm>
+
+#define dname(dir) ((dir)==Arts::input?"input":"output")
+#define pstat \
+ printf("port name %s, direction %s, id %d\n",_Name.c_str(),dname(_Type.direction),_ID);
+
+void PortDesc_impl::constructor(ModuleDesc parent, const string& name,
+ const PortType& type)
+{
+#if 0
+ if(parent)
+ {
+ char * pname = parent->Name();
+ describe("PortDesc."+string(pname)+string(".")+name);
+ }
+ else
+ {
+ describe("PortDesc.Structure."+name);
+ }
+#endif
+ _name = name;
+ _type = type;
+ _parent = parent;
+ _isConnected = false;
+ _hasValue = false;
+ _value.type = _type.dataType;
+
+ if(!parent.isNull())
+ {
+ StructureDesc sd = parent.parent();
+ _ID = sd.obtainID();
+ }
+ // else: assume that some smart object which derives from us will set the ID accordingly
+ // -> for instance StructurePortDesc_impl does so
+}
+
+#if 0 /* PORT */
+void PortDesc_impl::cleanUp()
+{
+ disconnectAll();
+ delete _Connections;
+}
+#endif
+
+/*
+ * This is new and related to weak references, it purges all null references from _connections
+ */
+void PortDesc_impl::removeNullConnections()
+{
+ vector<PortDesc_wref>::iterator i = _connections.begin();
+
+ while(i != _connections.end())
+ {
+ PortDesc pd = *i;
+ if(pd.isNull())
+ {
+ _connections.erase(i);
+ i = _connections.begin();
+ printf("removeNullConnections() removed something (shouldn't happen)\n");
+ }
+ else i++;
+ }
+
+ _isConnected = !_connections.empty();
+}
+
+void PortDesc_impl::disconnectAll()
+{
+ // disconnect all connected ports
+ while(!_connections.empty())
+ {
+ PortDesc pd = _connections.front();
+
+ if(pd.isNull()) // weak references can automatically disappear
+ _connections.erase(_connections.begin());
+ else
+ pd.disconnectFrom(self());
+ }
+}
+
+PortDesc_impl::~PortDesc_impl()
+{
+}
+
+// Implementation for interface PortDesc
+long PortDesc_impl::ID()
+{
+ return _ID;
+}
+
+ModuleDesc PortDesc_impl::parent()
+{
+ return _parent;
+}
+
+string PortDesc_impl::name()
+{
+ return _name;
+}
+
+PortType PortDesc_impl::type()
+{
+ return _type;
+}
+
+bool PortDesc_impl::isConnected()
+{
+ if(_isConnected) removeNullConnections();
+ return _isConnected;
+}
+
+bool PortDesc_impl::hasValue()
+{
+ return _hasValue;
+}
+
+void PortDesc_impl::hasValue(bool newvalue)
+{
+ if(_hasValue != newvalue)
+ {
+ assert(newvalue == false);
+ _hasValue = newvalue;
+ }
+}
+
+vector<PortDesc> *PortDesc_impl::connections()
+{
+ vector<PortDesc_wref>::iterator i;
+ vector<PortDesc> *result = new vector<PortDesc>;
+
+ for(i = _connections.begin(); i != _connections.end(); i++)
+ {
+ PortDesc pd = *i;
+ if(!pd.isNull()) result->push_back(pd);
+ }
+ return result;
+}
+
+float PortDesc_impl::floatValue()
+{
+ assert(_hasValue);
+ assert(_type.dataType == "float");
+
+ Buffer b;
+ b.write(_value.value);
+ return b.readFloat();
+}
+
+void PortDesc_impl::floatValue( float _new_value )
+{
+ assert(!_isConnected);
+ assert(_type.direction == Arts::input);
+ assert(_type.dataType == "float");
+ assert(_value.type == "float");
+
+ Buffer b;
+ b.writeFloat(_new_value);
+ b.read(_value.value, b.size());
+ _hasValue = true;
+}
+
+string PortDesc_impl::stringValue()
+{
+ assert(_hasValue);
+ assert(_type.dataType == "string");
+ assert(_value.type == "string");
+
+ string result;
+ Buffer b;
+ b.write(_value.value);
+ b.readString(result);
+ return result;
+}
+
+void PortDesc_impl::stringValue( const string& _new_value )
+{
+ assert(!_isConnected); // shouldn't happen, but check anyway
+ assert(_type.direction == Arts::input);
+ assert(_type.dataType == "string");
+
+ Buffer b;
+ b.writeString(_new_value);
+ b.read(_value.value, b.size());
+ _hasValue = true;
+}
+
+Any PortDesc_impl::value()
+{
+ assert(_hasValue);
+ return _value;
+}
+
+void PortDesc_impl::value( const Any& _new_value )
+{
+ _value = _new_value;
+ _hasValue = true;
+}
+
+bool PortDesc_impl::connectTo( PortDesc port )
+{
+ removeNullConnections();
+
+ // check if we are already connected to that port:
+
+ unsigned long i;
+ for(i=0;i<_connections.size();i++)
+ {
+ PortDesc pd = _connections[i];
+ if(pd.ID() == port.ID()) return true;
+ }
+
+ const PortType& rType = port.type();
+
+ // only stream or event channels may be connected
+ if( _type.connType != rType.connType )
+ return false;
+
+ // TODO: eventually check conditions when it is legal to connect property
+ // ports, and when it is insane (_Type.connType == Arts::property)
+ //
+ // for incoming structure ports, for instance, it is perfectly allright
+
+ // only same data type connections allowed
+ if( _type.dataType != rType.dataType )
+ return false;
+
+ // only opposite directions
+ if( _type.direction == rType.direction )
+ return false;
+
+ // always first connect the input port to the output port and
+ // then the other direction
+
+ if( _type.direction == Arts::input )
+ {
+ if(!_isConnected || _type.isMultiPort)
+ {
+ assert(_connections.empty() || _type.isMultiPort);
+ _connections.push_back(port);
+
+ port.internalConnectInput(self());
+
+ _isConnected = true;
+ _hasValue = false;
+ return true;
+ }
+ }
+ if( _type.direction == Arts::output )
+ return port.connectTo(self());
+
+ return false;
+}
+
+void PortDesc_impl::internalConnectInput( PortDesc port )
+{
+ _connections.push_back(port);
+ _isConnected = true;
+}
+
+void PortDesc_impl::disconnectFrom( PortDesc port )
+{
+ removeNullConnections();
+
+ unsigned long found = 0;
+
+ artsdebug("port %ld disconnecting from port %ld\n",ID(),port.ID());
+
+ vector<PortDesc_wref>::iterator i = _connections.begin();
+ while(!found && i != _connections.end())
+ {
+ Arts::PortDesc other = *i;
+ if(!other.isNull() && other.ID() == port.ID())
+ {
+ _connections.erase(i);
+ i = _connections.begin();
+ found++;
+ }
+ else i++;
+ }
+
+ _isConnected = !_connections.empty();
+
+ ModuleDesc parent = _parent;
+ if(parent.isNull())
+ artsdebug("_Parent = <some structure>, isConnected = %d\n",_isConnected);
+ else
+ artsdebug("_Parent = %s, isConnected = %d\n",parent.name().c_str(),_isConnected);
+
+ if(found)
+ port.disconnectFrom(self());
+}
+
+// Implementation for interface ModuleDesc
+long ModuleDesc_impl::ID()
+{
+ return _ID;
+}
+
+StructureDesc ModuleDesc_impl::parent()
+{
+ return _parent;
+}
+
+string ModuleDesc_impl::name()
+{
+ return _name;
+}
+
+vector<PortDesc> *ModuleDesc_impl::ports()
+{
+ return new vector<PortDesc>(_ports);
+}
+
+long ModuleDesc_impl::x()
+{
+ return _x;
+}
+
+long ModuleDesc_impl::y()
+{
+ return _y;
+}
+
+long ModuleDesc_impl::width()
+{
+ assert(false);
+ return 0;
+}
+
+long ModuleDesc_impl::height()
+{
+ assert(false);
+ return 0;
+}
+
+
+bool ModuleDesc_impl::moveTo( long x, long y )
+{
+ // FIXME: collision checking!
+ _x = x;
+ _y = y;
+
+ return(true);
+}
+
+
+// Implementation for interface StructureDesc
+long StructureDesc_impl::width()
+{
+ assert(false);
+ return 0;
+}
+
+long StructureDesc_impl::height()
+{
+ assert(false);
+ return 0;
+}
+
+/*
+ * Query the module for it's paramenters
+ */
+
+void ModuleDesc_impl::constructor( StructureDesc parent,
+ const Arts::ModuleInfo& info )
+{
+ _name = info.name;
+ _x = -1; // no position assigned
+ _y = -1;
+ _ID = parent.obtainID();
+ _parent = parent;
+ _isInterface = info.isInterface;
+ _isStructure = info.isStructure;
+
+ collectPorts(info);
+}
+
+ModuleDesc_impl::~ModuleDesc_impl()
+{
+}
+
+bool ModuleDesc_impl::isInterface()
+{
+ return _isInterface;
+}
+
+bool ModuleDesc_impl::isStructure()
+{
+ return _isStructure;
+}
+
+
+PortDesc ModuleDesc_impl::findPort(const string& name)
+{
+ vector<PortDesc>::iterator p;
+
+ for(p = _ports.begin(); p != _ports.end(); p++)
+ {
+ if(name == p->name()) return *p;
+ }
+
+ return PortDesc::null();
+}
+
+long ModuleDesc_impl::collectPorts( const Arts::ModuleInfo& info )
+{
+ vector<PortType>::const_iterator i;
+ vector<string>::const_iterator ni = info.portnames.begin();
+ long portcount = 0;
+
+ for(i=info.ports.begin(); i != info.ports.end(); i++)
+ {
+ const PortType& porttype = *i;
+ const string& portname = *ni++;
+
+ artsdebug("#%d: %s\n",portcount,portname.c_str());
+
+ PortDesc pd(self(),portname,porttype);
+ _ports.push_back(pd);
+ portcount++;
+ }
+ return(portcount);
+}
+
+ModuleDesc StructureDesc_impl::createModuleDesc( const ModuleInfo& info )
+{
+ Arts::ModuleDesc result = createModuleDesc(info.name);
+
+ assert(!result.isNull());
+ return result;
+}
+
+ModuleDesc StructureDesc_impl::createModuleDesc( const string& name )
+{
+ /* FIXME: need new comment
+ * to create a representation of a specified synth module, we
+ *
+ * - create an instance of this synth module by contacting the
+ * module server and telling him to do so (result is a C++ class)
+ *
+ * - create an instance of a ModuleDesc, and tell it to query the
+ * module for it's parameters (result is a CORBA object)
+ *
+ * - destroy the synth module (C++ class) again and return a reference
+ * to the CORBA object
+ */
+/*
+ ModuleServer<SynthModule> *MS_SynthModule;
+ MS_SynthModule = (ModuleServer<SynthModule> *)SynthModule::get_MS();
+
+ SynthModule *m = (SynthModule *)MS_SynthModule->getModule(name);
+*/
+#if 0
+ Arts::ModuleInfo_var info = ModuleBroker->lookupModule(name);
+ if(!info) return 0;
+#endif
+ const Arts::ModuleInfo& info = makeModuleInfo(name);
+ Arts::ModuleDesc moduledesc = ModuleDesc(self(),info);
+ _modules.push_back(moduledesc);
+ return moduledesc;
+}
+
+void StructureDesc_impl::freeModuleDesc(ModuleDesc moduledesc)
+{
+ vector<ModuleDesc>::iterator i;
+
+ for(i=_modules.begin();i != _modules.end(); i++)
+ {
+ Arts::ModuleDesc current = *i;
+
+ if(current.ID() == moduledesc.ID())
+ {
+ _modules.erase(i); // will get freed automagically
+ return;
+ }
+ }
+}
+
+vector<ModuleDesc> *StructureDesc_impl::modules()
+{
+ vector<ModuleDesc> *retval = new vector<ModuleDesc>(_modules);
+ return(retval);
+}
+
+void StructureDesc_impl::addInheritedInterface(const string& iface)
+{
+ _inheritedInterfaces.push_back(iface);
+}
+
+void StructureDesc_impl::removeInheritedInterface(const string& iface)
+{
+ vector<string> newII;
+ vector<string>::iterator ii;
+
+ for(ii = _inheritedInterfaces.begin(); ii != _inheritedInterfaces.end(); ii++)
+ if(*ii != iface)
+ newII.push_back(*ii);
+
+ _inheritedInterfaces = newII;
+}
+
+vector<string> *StructureDesc_impl::inheritedInterfaces()
+{
+ return new vector<string>(_inheritedInterfaces);
+}
+
+StructureDesc_impl::StructureDesc_impl()
+{
+ arts_debug("PORT: created structuredesc_impl");
+ nextID = 0;
+ _valid = true;
+ _externalInterface.name = "unknown"; // FIXME
+ _externalInterface.isStructure = true;
+ _externalInterface.isInterface = false;
+}
+
+StructureDesc_impl::~StructureDesc_impl()
+{
+ artsdebug("StructureDesc released...\n");
+}
+
+long StructureDesc_impl::obtainID()
+{
+ return(nextID++);
+}
+
+bool StructureDesc_impl::valid()
+{
+ return(_valid);
+}
+
+void StructureDesc_impl::clear()
+{
+ _modules.clear();
+ _ports.clear();
+ _inheritedInterfaces.clear();
+ _valid = true;
+}
+
+// "file" management
+
+vector<string> *PortDesc_impl::saveToList()
+{
+ vector<string> *list = new vector<string>;
+
+ sqprintf(list,"id=%ld",_ID);
+ if(_hasValue)
+ {
+ if(_type.dataType == "string")
+ {
+ sqprintf(list,"string_data=%s",stringValue().c_str());
+ }
+ else if(_type.dataType == "float")
+ {
+ sqprintf(list,"audio_data=%2.5f",floatValue());
+ }
+ else
+ {
+ Buffer b;
+ _value.writeType(b);
+ sqprintf(list,"any_data=%s",b.toString("value").c_str());
+ }
+ }
+
+ if(_isConnected)
+ {
+ vector<PortDesc_wref>::iterator i;
+
+ for(i=_connections.begin();i != _connections.end(); i++)
+ {
+ Arts::PortDesc port = *i;
+ if(!port.isNull()) sqprintf(list,"connect_to=%ld",port.ID());
+ }
+ }
+ return list;
+}
+
+vector<string> *ModuleDesc_impl::saveToList()
+{
+ vector<string> *list = new vector<string>;
+ vector<PortDesc>::iterator i;
+
+ sqprintf(list,"id=%ld",_ID);
+ sqprintf(list,"x=%ld",_x);
+ sqprintf(list,"y=%ld",_y);
+ for(i=_ports.begin();i != _ports.end();i++)
+ {
+ PortDesc pd = *i;
+ sqprintf(list,"port=%s",pd.name().c_str());
+
+ vector<string> *portlist = pd.saveToList();
+ addSubStringSeq(list,portlist);
+ delete portlist;
+ }
+ return list;
+}
+
+vector<string> *StructureDesc_impl::saveToList()
+{
+ vector<string> *list = new vector<string>;
+ vector<ModuleDesc>::iterator mi;
+ vector<StructurePortDesc>::iterator pi;
+ vector<string>::iterator ii;
+
+ sqprintf(list,"name=%s",_externalInterface.name.c_str());
+ for(mi=_modules.begin();mi != _modules.end();mi++)
+ {
+ ModuleDesc md = *mi;
+ sqprintf(list,"module=%s",md.name().c_str());
+
+ vector<string> *modulelist = md.saveToList();
+ addSubStringSeq(list,modulelist);
+ delete modulelist;
+ }
+ for(pi=_ports.begin(); pi!=_ports.end(); pi++)
+ {
+ Arts::StructurePortDesc spd = *pi;
+ sqprintf(list,"structureport");
+
+ vector<string> *portlist= spd.saveToList();
+ addSubStringSeq(list,portlist);
+ delete portlist;
+ }
+ for(ii=_inheritedInterfaces.begin(); ii != _inheritedInterfaces.end(); ii++)
+ sqprintf(list,"interface=%s",ii->c_str());
+
+ return list;
+}
+
+void PortDesc_impl::internalReConnect( const vector<PortDesc>& allports )
+{
+ vector<PortDesc>::const_iterator i;
+
+ for(i=allports.begin(); i != allports.end(); i++)
+ {
+ PortDesc pd = (*i);
+ long oid = pd.internalOldID();
+
+ if(find(oldConnections.begin(),oldConnections.end(),oid)
+ != oldConnections.end())
+ {
+ connectTo(pd);
+ }
+ }
+}
+
+long PortDesc_impl::internalOldID()
+{
+ return _oldID;
+}
+
+void PortDesc_impl::loadFromList(const vector<string>& list)
+{
+ unsigned long i;
+ string cmd,param;
+ for(i=0;i<list.size();i++)
+ {
+ if(parse_line(list[i],cmd,param)) // otherwise: empty or comment
+ {
+ if(cmd == "audio_data") {
+ floatValue(atof(param.c_str()));
+ } else if(cmd == "string_data") {
+ stringValue(param);
+ } else if(cmd == "any_data") {
+ Buffer b;
+ if(b.fromString(param,"value"))
+ {
+ Any any;
+ any.readType(b);
+ if(!b.readError() && !b.remaining())
+ value(any);
+ }
+ } else if(cmd == "id") {
+ _oldID = atol(param.c_str());
+ } else if(cmd == "connect_to") {
+ oldConnections.push_back(atol(param.c_str()));
+ }
+ }
+ }
+}
+
+void ModuleDesc_impl::loadFromList(const vector<string>& list)
+{
+ artsdebug("mlist-----------\n");
+ unsigned long i;
+ string cmd, param;
+ for(i=0;i<list.size();i++)
+ {
+ if(parse_line(list[i],cmd,param)) // otherwise: empty or comment
+ {
+ artsdebug("MD: load-> cmd was %s\n",cmd.c_str());
+ if(cmd == "port")
+ {
+ string portName =
+ OldFormatTranslator::newPortName(_name,param);
+ PortDesc pd = PortDesc::null();
+ vector<PortDesc>::iterator pi;
+
+ for(pi=_ports.begin(); pi != _ports.end(); pi++)
+ {
+ artsdebug("pdi = %s, portName = %s\n",pi->name().c_str(),
+ portName.c_str());
+ if(pi->name() == portName) pd = *pi;
+ }
+ assert(!pd.isNull());
+
+ vector<string> *plist = getSubStringSeq(&list,i);
+ pd.loadFromList(*plist);
+ delete plist;
+ } else if(cmd == "x") {
+ _x = atol(param.c_str());
+ artsdebug("X set to %ld (param was %s)\n",_x,param.c_str());
+ } else if(cmd == "y") {
+ _y = atol(param.c_str());
+ artsdebug("Y set to %ld (param was %s)\n",_y,param.c_str());
+ }
+ }
+ }
+ artsdebug("-----------mlist\n");
+}
+
+void StructureDesc_impl::loadFromList(const vector<string>& list)
+{
+ string cmd,param;
+ unsigned long i;
+ vector<PortDesc> allports;
+
+ clear();
+ _externalInterface.name = (const char *)"unknown";
+
+ artsdebug("loadFromList; listlen = %ld\n",list.size());
+ for(i=0;i<list.size();i++)
+ {
+ if(parse_line(list[i],cmd,param)) // otherwise: empty or comment
+ {
+ artsdebug("SD: load-> cmd was %s\n",cmd.c_str());
+ if(cmd == "module")
+ {
+ string newName = OldFormatTranslator::newModuleName(param);
+ ModuleDesc md = createModuleDesc(newName);
+
+ vector<string> *mlist = getSubStringSeq(&list,i);
+
+ if(!md.isNull())
+ {
+ md.loadFromList(*mlist);
+
+ // PORT: order changed
+ vector<PortDesc> *pd = md.ports();
+ vector<PortDesc>::iterator pi;
+ for(pi = pd->begin(); pi != pd->end();pi++)
+ allports.push_back(*pi);
+
+ delete pd;
+ }
+ else
+ {
+ // module couldn't be found
+ _valid = false;
+ }
+ delete mlist;
+ }
+ else if(cmd == "name")
+ {
+ _externalInterface.name = param;
+ }
+ else if(cmd == "interface")
+ {
+ _inheritedInterfaces.push_back(param);
+ }
+ else if(cmd == "structureport")
+ {
+ // just to have valid values to pass to the new (to be loaded)
+ // port:
+ PortType type;
+ type.direction = Arts::input;
+ type.dataType = "float";
+ type.connType = Arts::conn_stream;
+ type.isMultiPort = false;
+
+ StructurePortDesc spd =
+ createStructurePortDesc(type,"unknown");
+
+ vector<string> *splist = getSubStringSeq(&list,i);
+ spd.loadFromList(*splist);
+ delete splist;
+
+ // yes; this is a port as well
+ allports.push_back(spd);
+ }
+ }
+ }
+
+ for(i=0;i<allports.size();i++)
+ allports[i].internalReConnect(allports);
+}
+
+void StructureDesc_impl::name(const string& name)
+{
+ _externalInterface.name = name;
+}
+
+string StructureDesc_impl::name()
+{
+ return _externalInterface.name;
+}
+
+long extint_pscore(StructurePortDesc p)
+{
+ long result = p.position(); //p->X()*1000+p->Y();
+ if(p.type().direction == Arts::input) result += 5000000;
+
+ return result;
+}
+
+bool extint_port_compare(StructurePortDesc p1, StructurePortDesc p2)
+{
+ long p1s = extint_pscore(p1);
+ long p2s = extint_pscore(p2);
+
+ artsdebug("compare; [%s] = %d ; [%s] = %d\n", p1.name().c_str(),p1s,
+ p2.name().c_str(),p2s);
+ return (p1s < p2s);
+// return -1;
+ //if(p1s == p2s) return 0;
+ //return 1;
+}
+
+ModuleInfo StructureDesc_impl::externalInterface()
+{
+ ModuleInfo result = _externalInterface;
+ vector<StructurePortDesc> sorted_ports = _ports;
+ vector<StructurePortDesc>::iterator p;
+ unsigned long l;
+/* PORT:
+ for(l=0;l<_Ports->length();l++) sorted_ports.push_back((*_Ports)[l]);
+*/
+ sort(sorted_ports.begin(),sorted_ports.end(),extint_port_compare);
+
+ l = 0;
+ for(p=sorted_ports.begin();p != sorted_ports.end();p++)
+ {
+ string pname = p->name();
+ PortType ptype = p->type();
+
+ if(ptype.direction == Arts::input)
+ ptype.direction = Arts::output;
+ else
+ ptype.direction = Arts::input;
+
+ artsdebug("externalInterface; sorted ports: %d => %s\n",l,pname.c_str());
+ result.ports.push_back(ptype);
+ result.portnames.push_back(pname);
+ l++;
+ }
+ return result;
+}
+
+vector<StructurePortDesc> *StructureDesc_impl::ports()
+{
+ return new vector<StructurePortDesc>(_ports);
+}
+
+StructurePortDesc StructureDesc_impl::createStructurePortDesc(
+ const Arts::PortType& type, const string& name)
+{
+ artsdebug("creating new port %s\n",name.c_str());
+ StructurePortDesc port(self(), name, type);
+ _ports.push_back(port);
+
+ // set the Position (put it at the end of the ports)
+ unsigned long i, count = 0;
+ for(i=0;i<_ports.size();i++)
+ {
+ if(_ports[i].type().direction == type.direction) count++;
+ }
+ assert(count > 0); // we just inserted one ;)
+ port.internalSetPosition(count-1);
+ return port;
+}
+
+void StructureDesc_impl::freeStructurePortDesc(StructurePortDesc portdesc)
+{
+ vector<StructurePortDesc>::iterator i;
+
+ for(i=_ports.begin(); i != _ports.end(); i++)
+ {
+ if(i->ID() == portdesc.ID())
+ {
+ _ports.erase(i);
+ return;
+ }
+ }
+}
+
+void StructureDesc_impl::moveStructurePortDesc(StructurePortDesc
+ portdesc, long newposition)
+{
+ const Arts::PortType& type = portdesc.type();
+
+ unsigned long i;
+ long count = 0;
+ for(i=0;i<_ports.size();i++)
+ {
+ if(_ports[i].type().direction == type.direction) count++;
+ }
+
+ if(newposition < 0) newposition = 0;
+ if(newposition > count-1) newposition = count-1;
+
+ if(newposition == portdesc.position()) return;
+
+ int delta, lower, upper;
+
+ if(newposition > portdesc.position())
+ {
+ // if the port gets a higher position, move all ports that
+ // are between it's current position and its new position down one
+ lower = portdesc.position();
+ upper = newposition;
+ delta = -1;
+ }
+ else
+ {
+ // if the port gets a lower position, move all ports that
+ // are between it's current position and its new position up one
+ lower = newposition;
+ upper = portdesc.position();
+ delta = 1;
+ }
+
+ for(i=0;i<_ports.size();i++)
+ {
+ StructurePortDesc pd = _ports[i];
+
+ if(pd.type().direction == type.direction)
+ {
+ if(pd.ID() != portdesc.ID() &&
+ pd.position() >= lower && pd.position() <= upper)
+ {
+ pd.internalSetPosition(pd.position()+delta);
+ }
+ }
+
+ }
+ portdesc.internalSetPosition(newposition);
+}
+
+void StructurePortDesc_impl::constructor(StructureDesc parent,
+ const string& name, const PortType& type)
+{
+ PortDesc_impl::constructor(ModuleDesc::null(),name,type);
+ _parentStructure = parent;
+ _ID = parent.obtainID();
+ _x = 0;
+ _y = 0;
+ _position = 0;
+}
+
+StructurePortDesc_impl::~StructurePortDesc_impl()
+{
+ // this destructor is required to make some compilers (egcs-1.1.2) compile
+}
+
+long StructurePortDesc_impl::x()
+{
+ return _x;
+}
+
+long StructurePortDesc_impl::y()
+{
+ return _y;
+}
+
+long StructurePortDesc_impl::position()
+{
+ return _position;
+}
+
+void StructurePortDesc_impl::lowerPosition()
+{
+ StructureDesc parent = _parentStructure; // weak reference
+
+ if(!parent.isNull())
+ parent.moveStructurePortDesc(self(), _position-1);
+}
+
+void StructurePortDesc_impl::raisePosition()
+{
+ StructureDesc parent = _parentStructure; // weak reference
+
+ if(!parent.isNull())
+ parent.moveStructurePortDesc(self(), _position+1);
+}
+
+void StructurePortDesc_impl::rename(const string& newname)
+{
+ _name = newname;
+}
+
+void StructurePortDesc_impl::inheritedInterface(const string& iface)
+{
+ _inheritedInterface = iface;
+}
+
+string StructurePortDesc_impl::inheritedInterface()
+{
+ return _inheritedInterface;
+}
+
+// only used by the structure to reorder the ports
+void StructurePortDesc_impl::internalSetPosition(long position)
+{
+ _position = position;
+}
+
+StructureDesc StructurePortDesc_impl::parentStructure()
+{
+ return _parentStructure;
+}
+
+bool StructurePortDesc_impl::moveTo( long X, long Y )
+{
+ // FIXME: check space
+ _x = X;
+ _y = Y;
+
+ return true;
+}
+
+/*
+ override load & save behaviour this kind of port requires that we save the type
+ of the port as well, that means all of the porttype:
+
+ enum PortDirection {input, output};
+ enum PortDataType {audio_data, string_data};
+ enum PortConnType {stream, event, property};
+ struct PortType {
+ PortDirection direction;
+ PortDataType dataType;
+ PortConnType connType;
+ };
+
+ so when saved, it will look like that:
+
+ {
+ name=fasel
+ x=4
+ y=2
+ type
+ {
+ direction=input/output
+ datatype=audio/string
+ conntype=stream/event/property
+ }
+ data
+ {
+ [original port saves here]
+ }
+ }
+*/
+
+PortType loadTypeFromList(const vector<string>& list)
+{
+ unsigned long i,loadstate = 0;
+ string cmd,param;
+ Arts::PortType result;
+
+ for(i=0;i<list.size();i++)
+ {
+ if(parse_line(list[i],cmd,param)) // otherwise: empty or comment
+ {
+ artsdebug("PortType: load-> cmd was %s\n",cmd.c_str());
+ if(cmd == "direction")
+ {
+ if(param == "input") {
+ result.direction = Arts::input;
+ }
+ else if(param == "output") {
+ result.direction = Arts::output;
+ }
+ else assert(false);
+
+ loadstate += 1;
+ } else if(cmd == "datatype") {
+ if(param == "audio") {
+ result.dataType = "float";
+ }
+ else if(param == "string") {
+ result.dataType = "string";
+ }
+ else assert(false);
+
+ loadstate += 100;
+ } else if(cmd == "conntype") {
+ if(param == "stream") {
+ result.connType = Arts::conn_stream;
+ }
+ else if(param == "event") {
+ result.connType = Arts::conn_event;
+ }
+ else if(param == "property") {
+ result.connType = Arts::conn_property;
+ artsdebug("got property stuff\n");
+ }
+ else assert(false);
+
+ loadstate += 10000;
+ }
+ }
+ }
+ assert(loadstate == 10101); // should see every member exactly once
+ result.isMultiPort = false;
+ return result;
+}
+
+void StructurePortDesc_impl::loadFromList(const vector<string>& list)
+{
+ artsdebug("structureportlist-----------\n");
+ unsigned long i;
+ string cmd,param;
+ vector<string> *typelist = 0, *datalist = 0;
+ bool haveType = false, haveData = false;
+ // need both to do restore, type first
+
+ for(i=0;i<list.size();i++)
+ {
+ if(parse_line(list[i],cmd,param)) // otherwise: empty or comment
+ {
+ artsdebug("StructurePortDesc: load-> cmd was %s\n",cmd.c_str());
+ if(cmd == "type")
+ {
+ assert(!haveType); // only allowed once
+ haveType = true;
+ typelist = getSubStringSeq(&list,i);
+ } else if(cmd == "data") {
+ assert(!haveData); // only allowed once
+ haveData = true;
+ datalist = getSubStringSeq(&list,i);
+ } else if(cmd == "x") {
+ _x = atol(param.c_str());
+ artsdebug("X set to %ld (param was %s)\n",_x,param.c_str());
+ } else if(cmd == "y") {
+ _y = atol(param.c_str());
+ artsdebug("Y set to %ld (param was %s)\n",_y,param.c_str());
+ } else if(cmd == "position") {
+ _position = atol(param.c_str());
+ artsdebug("Position set to %ld (param was %s)\n",_position,
+ param.c_str());
+ } else if(cmd == "name") {
+ _name = param;
+ artsdebug("Name set to %s\n",_name.c_str());
+ } else if(cmd == "interface") {
+ _inheritedInterface = param;
+ artsdebug("Interface set to %s\n",_inheritedInterface.c_str());
+ }
+ }
+ }
+ assert(haveType && haveData);
+
+ _type = loadTypeFromList(*typelist);
+
+ if(_type.connType == Arts::conn_property) artsdebug("have property here\n");
+ PortDesc_impl::loadFromList(*datalist);
+
+ delete typelist;
+ delete datalist;
+ artsdebug("-----------structureportlist\n");
+}
+
+vector<string> *saveTypeToList(const PortType& type)
+{
+ vector<string> *list = new vector<string>;
+
+ switch(type.direction)
+ {
+ case Arts::input: sqprintf(list,"direction=input");
+ break;
+ case Arts::output: sqprintf(list,"direction=output");
+ break;
+ default: assert(false); // should never happen!
+ }
+ if(type.dataType == "float")
+ {
+ sqprintf(list,"datatype=audio");
+ }
+ else if(type.dataType == "string")
+ {
+ sqprintf(list,"datatype=string");
+ }
+ else
+ {
+ assert(false); // should never happen!
+ }
+ switch(type.connType)
+ {
+ case Arts::conn_stream: sqprintf(list,"conntype=stream");
+ break;
+ case Arts::conn_event: sqprintf(list,"conntype=event");
+ break;
+ case Arts::conn_property: sqprintf(list,"conntype=property");
+ break;
+ default: assert(false); // should never happen!
+ }
+
+ return list;
+}
+
+vector<string> *StructurePortDesc_impl::saveToList()
+{
+ vector<string> *list = new vector<string>;
+ sqprintf(list,"name=%s",_name.c_str());
+ sqprintf(list,"x=%ld",_x);
+ sqprintf(list,"y=%ld",_y);
+ sqprintf(list,"position=%ld",_position);
+
+ if(!_inheritedInterface.empty())
+ sqprintf(list, "interface=%s",_inheritedInterface.c_str());
+
+ sqprintf(list,"type");
+
+ vector<string> *typelist = saveTypeToList(_type);
+ addSubStringSeq(list,typelist);
+ delete typelist;
+
+ sqprintf(list,"data");
+
+ vector<string> *portlist = PortDesc_impl::saveToList();
+ addSubStringSeq(list,portlist);
+ delete portlist;
+
+ return list;
+}
diff --git a/arts/tools/Makefile.am b/arts/tools/Makefile.am
new file mode 100644
index 00000000..e503d54a
--- /dev/null
+++ b/arts/tools/Makefile.am
@@ -0,0 +1,82 @@
+
+SUBDIRS= . pics
+
+INCLUDES = \
+ -I$(top_srcdir)/arts/gui/kde \
+ -I$(top_builddir)/arts/gui/common \
+ -I$(top_builddir)/arts/modules \
+ -I$(top_builddir)/arts/modules/common \
+ -I$(top_builddir)/arts/modules/synth \
+ -I$(top_builddir)/arts/modules/mixers \
+ -I$(top_builddir)/arts/modules/effects \
+ -I$(top_builddir)/arts/midi \
+ -I$(kde_includes)/arts \
+ $(all_includes)
+
+
+lib_LTLIBRARIES = libartscontrolsupport.la libartscontrolapplet.la
+
+libartscontrolapplet_la_SOURCES = \
+ artscontrolapplet.cpp
+
+libartscontrolsupport_la_SOURCES = \
+ templateview.cpp artsactions.cpp \
+ audiomanager.cpp choosebusdlg.cpp \
+ midimanagerview.cpp midimanagerdlg.ui midimanagerwidget.ui \
+ midiportdlg.cpp midiinstdlg.cpp environmentview.cpp \
+ fftscopeview.cpp mediatypesview.cpp statusview.cpp
+
+METASOURCES = AUTO
+
+SOMAJOR = 1
+SOMINOR = 0
+SOSUBMINOR = 0
+
+libartscontrolapplet_la_LDFLAGS = $(all_libraries) -version-info $(SOMAJOR):$(SOMINOR):$(SOSUBMINOR) -no-undefined -module
+libartscontrolsupport_la_LDFLAGS = $(all_libraries) -version-info $(SOMAJOR):$(SOMINOR):$(SOSUBMINOR) -no-undefined
+
+libartscontrolapplet_la_LIBADD = \
+ -lartsflow -lartsflow_idl -lmcop -lqtmcop $(LIBDL) -lsoundserver_idl -lartskde \
+ $(LIB_KDEUI) ./libartscontrolsupport.la
+
+# Arnolds version with dynamic-linking for testing.
+#
+#libartscontrolsupport_la_LIBADD = \
+# -lartsflow -lartsflow_idl -lmcop -lqtmcop $(LIBDL) -lsoundserver_idl -lartskde \
+# $(top_builddir)/arts/gui/common/libartsgui_idl.la \
+# -L$(top_builddir)/arts/gui/kde -lartsgui_kde \
+# -L$(top_builddir)/arts/modules -lartsmodules \
+# $(LIB_KDEUI)
+
+libartscontrolsupport_la_LIBADD = \
+ -lartsflow -lartsflow_idl -lmcop -lqtmcop $(LIBDL) -lsoundserver_idl -lartskde \
+ $(top_builddir)/arts/gui/common/libartsgui_idl.la \
+ $(top_builddir)/arts/gui/kde/libartsgui_kde.la \
+ $(top_builddir)/arts/modules/libartsmodules.la \
+ $(LIB_KDEUI)
+
+bin_PROGRAMS = artscontrol
+artscontrol_SOURCES = main.cpp levelmeters.cpp
+artscontrol_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+artscontrol_LDADD = libartscontrolsupport.la \
+ $(LIB_KDEUI) $(LIB_KSYCOCA) $(LIB_KFILE) \
+ -lqtmcop -lartsflow_idl -lsoundserver_idl -lartskde
+
+xdg_apps_DATA = artscontrol.desktop
+
+lnkdir = $(kde_datadir)/kicker/applets
+lnk_DATA = artscontrolapplet.desktop
+
+rcdir = $(kde_datadir)/artscontrol
+rc_DATA = artscontrol.rc artsmidimanagerview.rc
+
+messages: rc.cpp
+ $(XGETTEXT) *.h *.cpp -o $(podir)/artscontrol.pot
+
+artsactions.lo: ../modules/artsmodules.h ../midi/artsmidi.h ../gui/common/artsgui.h ../modules/common/artsmodulescommon.h ../modules/synth/artsmodulessynth.h ../modules/effects/artsmoduleseffects.h ../modules/mixers/artsmodulesmixers.h
+artscontrolapplet.lo: ../gui/common/artsgui.h ../modules/effects/artsmoduleseffects.h ../modules/common/artsmodulescommon.h ../midi/artsmidi.h ../modules/synth/artsmodulessynth.h ../modules/artsmodules.h ../modules/mixers/artsmodulesmixers.h
+environmentview.lo: ../modules/artsmodules.h ../midi/artsmidi.h ../gui/common/artsgui.h ../modules/common/artsmodulescommon.h ../modules/synth/artsmodulessynth.h ../modules/effects/artsmoduleseffects.h ../modules/mixers/artsmodulesmixers.h
+fftscopeview.lo: ../modules/artsmodules.h ../midi/artsmidi.h ../gui/common/artsgui.h ../modules/common/artsmodulescommon.h ../modules/synth/artsmodulessynth.h ../modules/effects/artsmoduleseffects.h ../modules/mixers/artsmodulesmixers.h
+main.o: ../gui/common/artsgui.h ../modules/artsmodules.h ../midi/artsmidi.h ../modules/common/artsmodulescommon.h ../modules/synth/artsmodulessynth.h ../modules/effects/artsmoduleseffects.h ../modules/mixers/artsmodulesmixers.h
+midimanagerview.lo: ../midi/artsmidi.h ../modules/artsmodules.h ../gui/common/artsgui.h ../modules/common/artsmodulescommon.h ../modules/synth/artsmodulessynth.h ../modules/effects/artsmoduleseffects.h ../modules/mixers/artsmodulesmixers.h
+
diff --git a/arts/tools/artsactions.cpp b/arts/tools/artsactions.cpp
new file mode 100644
index 00000000..b75de027
--- /dev/null
+++ b/arts/tools/artsactions.cpp
@@ -0,0 +1,191 @@
+/*
+
+ Copyright (C) 2003 Arnold Krille <arnold@arnoldarts.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 "artsactions.h"
+
+#include <kaction.h>
+#include <kactioncollection.h>
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kglobal.h>
+//#include <kdebug.h>
+
+#include <kartsserver.h>
+
+#include "fftscopeview.h"
+#include "audiomanager.h"
+#include "statusview.h"
+#include "midimanagerview.h"
+#include "environmentview.h"
+#include "mediatypesview.h"
+
+ArtsActions::ArtsActions( KArtsServer* server, KActionCollection* col, QWidget* parent, const char* name )
+ : QObject( parent,name )
+ , _kartsserver( server )
+ , _actioncollection( col )
+ , _a_sv( 0 ), _a_am( 0 ), _a_asv( 0 ), _a_mmv( 0 ), _a_ev( 0 ), _a_mtv( 0 )
+// , _a_morebars( 0 ), _a_lessbars( 0 )
+ , _a_style_normal( 0 ), _a_style_fire( 0 ), _a_style_line( 0 ), _a_style_led( 0 ), _a_style_analog( 0 ), _a_style_small( 0 )
+ , _stylemenu( 0 )
+ , _sv( 0 ), _am( 0 ), _asv( 0 ), _mmv( 0 ), _ev( 0 ), _mtv( 0 )
+{
+ //kdDebug()<<k_funcinfo<<endl;
+ KGlobal::locale()->insertCatalogue( "artscontrol" );
+ if ( !_kartsserver ) _kartsserver = new KArtsServer( this );
+}
+
+ArtsActions::~ArtsActions() {
+ //kdDebug()<<k_funcinfo<<endl;
+ if ( _sv ) viewScopeView();
+ if ( _am ) viewAudioManager();
+ if ( _asv ) viewArtsStatusView();
+ if ( _mmv ) viewMidiManagerView();
+ if ( _ev ) viewEnvironmentView();
+ if ( _mtv ) viewMediaTypesView();
+}
+
+KAction* ArtsActions::actionScopeView() {
+ if ( !_a_sv ) _a_sv = new KAction( i18n( "&FFT Scope" ), "artsfftscope", KShortcut(), this, SLOT( viewScopeView() ), _actioncollection, "artssupport_view_scopeview" );
+ return _a_sv;
+}
+KAction* ArtsActions::actionAudioManager() {
+ if ( !_a_am ) _a_am = new KAction( i18n( "&Audio Manager" ), "artsaudiomanager", KShortcut(), this, SLOT( viewAudioManager() ), _actioncollection, "artssupport_view_audiomanager" );
+ return _a_am;
+}
+KAction* ArtsActions::actionArtsStatusView() {
+ if ( !_a_asv ) _a_asv = new KAction( i18n( "aRts &Status" ), "artscontrol", KShortcut(), this, SLOT( viewArtsStatusView() ), _actioncollection, "artssupport_view_artsstatus" );
+ return _a_asv;
+}
+KAction* ArtsActions::actionMidiManagerView() {
+ if ( !_a_mmv ) _a_mmv = new KAction( i18n( "&MIDI Manager" ), "artsmidimanager", KShortcut(), this, SLOT( viewMidiManagerView() ), _actioncollection, "artssupport_view_midimanager" );
+ return _a_mmv;
+}
+KAction* ArtsActions::actionEnvironmentView() {
+ if ( !_a_ev ) _a_ev = new KAction( i18n( "&Environment" ), "artsenvironment", KShortcut(), this, SLOT( viewEnvironmentView() ), _actioncollection, "artssupport_view_environment" );
+ return _a_ev;
+}
+KAction* ArtsActions::actionMediaTypesView() {
+ if ( !_a_mtv ) _a_mtv = new KAction( i18n( "Available Media &Types" ), "artsmediatypes", KShortcut(), this, SLOT( viewMediaTypesView() ), _actioncollection, "artssupport_view_mediatypes" );
+ return _a_mtv;
+}
+
+KAction* ArtsActions::actionStyleNormal() {
+ if ( !_a_style_normal ) _a_style_normal = new KAction( i18n( "Style: NormalBars" ), "", KShortcut(), this, SLOT( _p_style_normal() ), _actioncollection, "artssupport_style_normal" );
+ return _a_style_normal;
+}
+KAction* ArtsActions::actionStyleFire() {
+ if ( !_a_style_fire ) _a_style_fire = new KAction( i18n( "Style: FireBars" ), "", KShortcut(), this, SLOT( _p_style_fire() ), _actioncollection, "artssupport_style_fire" );
+ return _a_style_fire;
+}
+KAction* ArtsActions::actionStyleLine() {
+ if ( !_a_style_line ) _a_style_line = new KAction( i18n( "Style: LineBars" ), "", KShortcut(), this, SLOT( _p_style_line() ), _actioncollection, "artssupport_style_line" );
+ return _a_style_line;
+}
+KAction* ArtsActions::actionStyleLED() {
+ if ( !_a_style_led ) _a_style_led = new KAction( i18n( "Style: LEDs" ), "", KShortcut(), this, SLOT( _p_style_led() ), _actioncollection, "artssupport_style_led" );
+ return _a_style_led;
+}
+KAction* ArtsActions::actionStyleAnalog() {
+ if ( !_a_style_analog ) _a_style_analog = new KAction( i18n( "Style: Analog" ), "", KShortcut(), this, SLOT( _p_style_analog() ), _actioncollection, "artssupport_style_analog" );
+ return _a_style_analog;
+}
+KAction* ArtsActions::actionStyleSmall() {
+ if ( !_a_style_small ) _a_style_small = new KAction( i18n( "Style: Small" ), "", KShortcut(), this, SLOT( _p_style_small() ), _actioncollection, "artssupport_style_small" );
+ return _a_style_small;
+}
+KPopupMenu* ArtsActions::stylemenu() {
+ if ( !_stylemenu ) {
+ _stylemenu = new KPopupMenu();
+ KAction *tmp;
+ tmp = actionStyleNormal(); tmp->plug( _stylemenu );
+ tmp = actionStyleFire(); tmp->plug( _stylemenu );
+ tmp = actionStyleLine(); tmp->plug( _stylemenu );
+ tmp = actionStyleLED(); tmp->plug( _stylemenu );
+ tmp = actionStyleAnalog(); tmp->plug( _stylemenu );
+ tmp = actionStyleSmall(); tmp->plug( _stylemenu );
+ }
+ return _stylemenu;
+}
+
+KAction* ArtsActions::actionMoreBars( const QObject* receiver, const char* slot, KActionCollection *actioncollection ) {
+ static KAction *_a_morebars = new KAction( i18n( "More Bars in VU-Meters" ), "up", KShortcut(), receiver, slot, actioncollection, "artssupport_morebars" );
+ return _a_morebars;
+}
+KAction* ArtsActions::actionLessBars( const QObject* receiver, const char* slot, KActionCollection *actioncollection ) {
+ static KAction *_a_lessbars = new KAction( i18n( "Less Bars in VU-Meters" ), "down", KShortcut(), receiver, slot, actioncollection, "artssupport_lessbars" );
+ return _a_lessbars;
+}
+
+void ArtsActions::viewScopeView() {
+ if ( !_sv ) {
+ _sv = new FFTScopeView( _kartsserver->server() );
+ connect( _sv, SIGNAL( closed() ), this, SLOT( viewScopeView() ) );
+ } else {
+ delete _sv;
+ _sv = 0;
+ }
+}
+void ArtsActions::viewAudioManager() {
+ if ( !_am ) {
+ _am = new Gui_AUDIO_MANAGER();
+ connect( _am, SIGNAL( closed() ), this, SLOT( viewAudioManager() ) );
+ } else {
+ delete _am;
+ _am = 0;
+ }
+}
+void ArtsActions::viewArtsStatusView() {
+ if ( !_asv ) {
+ _asv = new ArtsStatusView( _kartsserver->server() );
+ connect( _asv, SIGNAL( closed() ), this, SLOT( viewArtsStatusView() ) );
+ } else {
+ delete _asv;
+ _asv = 0;
+ }
+}
+void ArtsActions::viewMidiManagerView() {
+ if ( !_mmv ) {
+ _mmv = new MidiManagerView();
+ connect( _mmv, SIGNAL( closed() ), this, SLOT( viewMidiManagerView() ) );
+ } else {
+ delete _mmv;
+ _mmv = 0;
+ }
+}
+void ArtsActions::viewEnvironmentView() {
+ if ( !_ev ) {
+ _ev = new EnvironmentView( defaultEnvironment() );
+ connect( _ev, SIGNAL( closed() ), this, SLOT( viewEnvironmentView() ) );
+ } else {
+ delete _ev;
+ _ev = 0;
+ }
+}
+void ArtsActions::viewMediaTypesView() {
+ if ( !_mtv ) {
+ _mtv = new MediaTypesView();
+ connect( _mtv, SIGNAL( closed() ), this, SLOT( viewMediaTypesView() ) );
+ } else {
+ delete _mtv;
+ _mtv = 0;
+ }
+}
+
+#include "artsactions.moc"
diff --git a/arts/tools/artsactions.h b/arts/tools/artsactions.h
new file mode 100644
index 00000000..c87945c2
--- /dev/null
+++ b/arts/tools/artsactions.h
@@ -0,0 +1,117 @@
+/*
+
+ Copyright (C) 2003 Arnold Krille <arnold@arnoldarts.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.
+
+ */
+
+#ifndef ARTS_ACTIONS_H
+#define ARTS_ACTIONS_H
+
+#include <qwidget.h>
+#include <kdelibs_export.h>
+class KArtsServer;
+class KAction;
+class KActionCollection;
+class KPopupMenu;
+class FFTScopeView;
+class Gui_AUDIO_MANAGER;
+class ArtsStatusView;
+class MidiManagerView;
+class EnvironmentView;
+class MediaTypesView;
+
+class KDE_EXPORT ArtsActions : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ Constructs a ArtsActions-object.
+
+ Use the KActions you get from it to obtain a unique Style for all menus.
+
+ It also provides an easy way to have FFT-ScopeView, Audiomanager and other things available.
+
+ @param artsserver a pointer to a existing KArtsServer. If 0 a new is created.
+ @param actioncollection the KActionCollection all the actions should belong to. Names of the actions are then: artssupport_*
+ @param qwidget the parent QWidget
+ @param name the name of the object
+ */
+ ArtsActions( KArtsServer* artsserver, KActionCollection* actioncollection, QWidget* qwidget, const char* name=0 );
+ /** Destructor */
+ ~ArtsActions();
+
+ /** Returns an Action for showing the ScopeView. Unless otherwise connected it also toggles a ScopeView. */
+ KAction* actionScopeView();
+ /** Returns an Action for showing the Audiomanager. Unless otherwise connected it also toggles a Audiomanager. */
+ KAction* actionAudioManager();
+ /** Returns an Action for showing the StatusView. Unless otherwise connected it also toggles a StatusView. */
+ KAction* actionArtsStatusView();
+ /** Returns an Action for showing the MidiManager. Unless otherwise connected it also toggles a MidiManager. */
+ KAction* actionMidiManagerView();
+ /** Returns an Action for showing the EnvironmentView. Unless otherwise connected it also toggles a EnvironmentView. */
+ KAction* actionEnvironmentView();
+ /** Returns an Action for showing the MediaTypesView. Unless otherwise connected it also toggles a MediaTypesView. */
+ KAction* actionMediaTypesView();
+
+ KAction* actionStyleNormal();
+ KAction* actionStyleFire();
+ KAction* actionStyleLine();
+ KAction* actionStyleLED();
+ KAction* actionStyleAnalog();
+ KAction* actionStyleSmall();
+ KPopupMenu* stylemenu();
+
+ static KAction* actionMoreBars( const QObject*, const char*, KActionCollection* );
+ static KAction* actionLessBars( const QObject*, const char*, KActionCollection* );
+
+public slots:
+ void viewScopeView();
+ void viewAudioManager();
+ void viewArtsStatusView();
+ void viewMidiManagerView();
+ void viewEnvironmentView();
+ void viewMediaTypesView();
+private slots:
+ void _p_style_normal() { emit styleNormal(); }
+ void _p_style_fire() { emit styleFire(); }
+ void _p_style_line() { emit styleLine(); }
+ void _p_style_led() { emit styleLED(); }
+ void _p_style_analog() { emit styleAnalog(); }
+ void _p_style_small() { emit styleSmall(); }
+signals:
+ void styleNormal();
+ void styleFire();
+ void styleLine();
+ void styleLED();
+ void styleAnalog();
+ void styleSmall();
+private:
+ KArtsServer* _kartsserver;
+ KActionCollection* _actioncollection;
+ KAction *_a_sv, *_a_am, *_a_asv, *_a_mmv, *_a_ev, *_a_mtv;
+ //KAction *_a_morebars, *_a_lessbars;
+ KAction *_a_style_normal, *_a_style_fire, *_a_style_line, *_a_style_led, *_a_style_analog, *_a_style_small;
+ KPopupMenu* _stylemenu;
+ FFTScopeView *_sv;
+ Gui_AUDIO_MANAGER *_am;
+ ArtsStatusView *_asv;
+ MidiManagerView *_mmv;
+ EnvironmentView *_ev;
+ MediaTypesView *_mtv;
+};
+
+#endif
diff --git a/arts/tools/artscontrol.desktop b/arts/tools/artscontrol.desktop
new file mode 100644
index 00000000..4c7068d8
--- /dev/null
+++ b/arts/tools/artscontrol.desktop
@@ -0,0 +1,136 @@
+[Desktop Entry]
+Name=aRts Control Tool
+Name[af]=Arts Kontrole Program
+Name[ar]=أداة aRts للتحكم
+Name[bn]=আর্ট্‌স্ নিয়ন্ত্রণ টুল
+Name[br]=Ostilh renadur aRts
+Name[bs]=Alat za podešavanje aRts-a
+Name[ca]=Eina de control de aRts
+Name[cs]=Ovládání programu aRts
+Name[cy]=Erfyn Rheoli aRts
+Name[da]=aRts-kontrolværktøj
+Name[de]=aRts-Steuerung
+Name[el]=Εργαλείο ελέγχου aRts
+Name[eo]=Sonservostirilo
+Name[et]=aRts'i juhtimine
+Name[eu]=aRts-en kontrol tresna
+Name[fa]=ابزار کنترل aRts
+Name[fi]=aRts-asetustyökalu
+Name[fr]=aRtsControl
+Name[ga]=Uirlis Rialaithe aRts
+Name[gl]=Ferramenta de Control de aRts
+Name[hi]=एआरटीएस नियंत्रक औज़ार
+Name[hr]=Podešavanje aRts-a
+Name[hu]=aRts vezérlőprogram
+Name[is]=Stjórnborð aRts
+Name[it]=Strumento di controllo di aRts
+Name[ja]=aRts コントロールツール
+Name[kk]=aRts басқару құралы
+Name[km]=ឧបករណ៍​បញ្ជា aRts
+Name[ko]=aRts 설정 도구
+Name[lt]=aRts valdymo įrankis
+Name[lv]=aRts Vadības Rīks
+Name[mk]=Контролна алатка на aRts
+Name[nb]=aRts-kontrollverktøy
+Name[nds]=aRts-Kuntrullwarktüüch
+Name[ne]=aRts नियन्त्रण उपकरण
+Name[nl]=aRts bedieningshulpprogramma
+Name[nn]=aRts-kontrollverktøy
+Name[pa]=aRts ਕੰਟਰੋਲ ਸੰਦ
+Name[pl]=Sterowanie aRts
+Name[pt]=Ferramenta de Controlo do aRts
+Name[pt_BR]=Ferramenta de Controle do aRts
+Name[ro]=Utilitar control aRts
+Name[ru]=artscontrol
+Name[se]=aRts-stivrenreaidu
+Name[sk]=Ovládací nástroj aRts
+Name[sl]=Orodje za nadzor aRts
+Name[sr]=Контролни алат aRts-а
+Name[sr@Latn]=Kontrolni alat aRts-a
+Name[sv]=Arts-kontrollverktyg
+Name[ta]=aRts கட்டுப்பாட்டுக் கருவி
+Name[tg]=aRts Асбоби Идоракунӣ
+Name[th]=เครื่องมือควบคุม aRts
+Name[tr]=aRts Denetim Aracı
+Name[uk]=Керування aRts
+Name[uz]=aRts boshqaruv vositasi
+Name[uz@cyrillic]=aRts бошқарув воситаси
+Name[ven]=Tshishumiswa tshau langula aRTs
+Name[xh]=Ulawulo Lwemizobo
+Name[zh_CN]=aRts 控制工具
+Name[zh_HK]=aRts 控制工具
+Name[zh_TW]=aRts 控制工具
+Name[zu]=Ithuluazi Lokuphatha le aRts
+GenericName=Sound Server Control
+GenericName[af]=Klank Bediener Kontrole
+GenericName[bg]=Контрол на аудио сървъра
+GenericName[bn]=সাউণ্ড সার্ভার নিয়ন্ত্রণ
+GenericName[br]=Kefluniañ ar Servijer Son
+GenericName[bs]=Kontrola sound servera
+GenericName[ca]=Control del servidor de so
+GenericName[cs]=Ovládání zvukového serveru
+GenericName[cy]=Rheoli Gweinydd Sain
+GenericName[da]=Lydserverkontrol
+GenericName[de]=Soundserver-Steuerung
+GenericName[el]=Έλεγχος εξυπηρετητή ήχου
+GenericName[eo]=Agordo de la sonservo
+GenericName[es]=Control del servidor de sonido
+GenericName[et]=Heliserveri seadistamine
+GenericName[eu]=Soinu zerbitzariaren kontrola
+GenericName[fa]=کنترل کارساز صدا
+GenericName[fi]=Äänipalvelimen hallinta
+GenericName[fr]=Contrôle du serveur de son
+GenericName[ga]=Rialú Freastalaí Fuaime
+GenericName[gl]=Control do Servidor de Son
+GenericName[he]=שליטה בשרת הצליל
+GenericName[hi]=ध्वनि सर्वर नियंत्रक
+GenericName[hr]=Kontrola zvučnog poslužitelja
+GenericName[hu]=Hangszolgáltatás-vezérlő
+GenericName[is]=Stillingar hljóðmiðlarans
+GenericName[it]=Controllo del server sonoro
+GenericName[ja]=サウンドサーバのコントロール
+GenericName[kk]=Дыбыс серверін басқару
+GenericName[km]=ឧបករណ៍​បញ្ជា​ម៉ាស៊ីន​បម្រើ​សំឡេង
+GenericName[ko]=소리 서버 설정
+GenericName[lt]=Garsų serverio valdymas
+GenericName[mk]=Контрола на серверот за звук
+GenericName[ms]=Kawalan Pelayan Bunyi
+GenericName[nb]=Lydtjenerkontroll
+GenericName[nds]=Klangserverstüern
+GenericName[ne]=ध्वनि सर्भर नियन्त्रण
+GenericName[nl]=Geluidsserverbediening
+GenericName[nn]=Lydtenarstyring
+GenericName[pa]=ਸਾਊਂਡ ਸਰਵਰ ਕੰਟਰੋਲ
+GenericName[pl]=Sterowanie serwerem dźwięku
+GenericName[pt]=Controlo do Servidor de Som
+GenericName[pt_BR]=Controle do servidor de som
+GenericName[ro]=Control server de sunet
+GenericName[ru]=Управление звуковым сервером
+GenericName[se]=Jietnabálvástivren
+GenericName[sk]=Nastavenie zvukového servera
+GenericName[sl]=Nadzor zvočnega strežnika
+GenericName[sr]=Контрола звучног сервера
+GenericName[sr@Latn]=Kontrola zvučnog servera
+GenericName[sv]=Inställning av ljudserver
+GenericName[ta]=ஒலி சேவையக கட்டுப்பாடு
+GenericName[tg]=Идоракунии Хидматрасони Овоз
+GenericName[th]=ควบคุมเซิร์ฟเวอร์เสียง
+GenericName[tr]=Ses Sunucu Yöneticisi
+GenericName[uk]=Керування сервером звуку
+GenericName[uz]=Tovush serverini boshqarish
+GenericName[uz@cyrillic]=Товуш серверини бошқариш
+GenericName[ven]=Ndangulo ya siva ya mubvumo
+GenericName[wa]=Contrôle do sierveu di sons
+GenericName[xh]=Ulawulo Lomncedisi Wesandi
+GenericName[zh_CN]=声音服务器控制
+GenericName[zh_HK]=聲音伺服器控制器
+GenericName[zh_TW]=聲音伺服器控制器
+GenericName[zu]=Ukulawila Lomlekeleli Womsindo
+Exec=artscontrol -caption "%c"
+Icon=artscontrol
+Type=Application
+Terminal=false
+X-DCOP-ServiceType=Multi
+DocPath=artsbuilder/index.html
+OnlyShowIn=KDE;
+Categories=Qt;KDE;AudioVideo;X-KDE-More;
diff --git a/arts/tools/artscontrol.rc b/arts/tools/artscontrol.rc
new file mode 100644
index 00000000..5c1c0368
--- /dev/null
+++ b/arts/tools/artscontrol.rc
@@ -0,0 +1,17 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="artscontrol" version="3">
+<MenuBar>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="artssupport_view_scopeview"/>
+ <Action name="artssupport_view_audiomanager"/>
+ <Action name="artssupport_view_artsstatus"/>
+ <Action name="artssupport_view_midimanager"/>
+ <Action name="artssupport_view_environment"/>
+ <Action name="artssupport_view_mediatypes"/>
+ <Action name="view_freeverb"/>
+ <Action name="old_volume_display"/>
+ <Separator />
+ <Action name="quit_artscontrol"/>
+ </Menu>
+</MenuBar>
+</kpartgui>
diff --git a/arts/tools/artscontrolapplet.cpp b/arts/tools/artscontrolapplet.cpp
new file mode 100644
index 00000000..a178c2d3
--- /dev/null
+++ b/arts/tools/artscontrolapplet.cpp
@@ -0,0 +1,163 @@
+/***************************************************************************
+ artscontrolapplet.cpp - description
+ -------------------
+ begin : Don Jan 30 20:42:53 CET 2003
+ copyright : (C) 2003 by Arnold Krille
+ email : arnold@arnoldarts.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. *
+ * *
+ ***************************************************************************/
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <qcursor.h>
+#include <qtimer.h>
+
+#include "artscontrolapplet.h"
+#include "artscontrolapplet_private.h"
+
+extern "C"
+{
+ KDE_EXPORT KPanelApplet* init( QWidget *parent, const QString configFile)
+ {
+ KGlobal::locale()->insertCatalogue("artscontrol");
+ return new ArtsControlApplet(configFile, KPanelApplet::Normal,
+ KPanelApplet::About /*| KPanelApplet::Help | KPanelApplet::Preferences*/,
+ parent, "artscontrolapplet");
+ }
+}
+
+ArtsControlApplet::ArtsControlApplet(const QString& configFile, Type type, int actions, QWidget *parent, const char *name) : KPanelApplet(configFile, type, actions, parent, name)
+{
+ //kdDebug()<<"ArtsControlApplet::ArtsControlApplet( const QString& "<<configFile<<", Type "<<type<<", int "<<actions<<", QWidget* "<<parent<<", const char* "<<name<<" )"<<endl;
+ // Get the current application configuration handle
+ ksConfig = config();
+
+ p = new ArtsControlAppletPrivate( this );
+ if( !p->barts ) KMessageBox::information(0, i18n("Something with the ArtsServer went wrong. You probably need to restart aRts and then reload this applet."));
+ setCustomMenu(p->menu);
+
+ p->layout = new QBoxLayout( this, QBoxLayout::LeftToRight );
+ p->layout->setSpacing( 2 );
+
+ if( p->barts ) {
+ p->vu = Arts::StereoVolumeControlGui( p->volume );
+ p->vu.label().fontsize( 8 );
+ p->vuw = new KArtsWidget( p->vu, this );
+ p->vuw->setMinimumSize( 16,16 );
+ p->layout->addWidget( p->vuw );
+ }
+
+ p->layout->activate();
+
+ QTimer::singleShot( 100, this, SLOT( supdatelayout() ) );
+
+kdDebug()<<"ArtsControlApplet::ArtsControlApplet() finished."<<endl;
+}
+
+ArtsControlApplet::~ArtsControlApplet() {
+kdDebug()<<k_funcinfo<<endl;
+}
+
+#include <kaboutdata.h>
+#include <kaboutapplication.h>
+
+void ArtsControlApplet::about() {
+ KAboutData about( "artscontrolapplet", I18N_NOOP( "aRts Control Applet" ), "0.5",
+ I18N_NOOP( "A kickerapplet to control aRts." ),
+ KAboutData::License_GPL, I18N_NOOP( "(c) 2003 by Arnold Krille" ) );
+ about.addAuthor( "Arnold Krille", I18N_NOOP( "Author of the Applet" ), "arnold@arnoldarts.de" );
+ about.addCredit( "Stefan Westerfeld", I18N_NOOP( "Thanks for creating aRts!" ) );
+ KAboutApplication a( &about, this );
+ a.exec();
+}
+
+void ArtsControlApplet::help() {
+kdDebug()<<k_funcinfo<<endl;
+}
+
+void ArtsControlApplet::preferences() {
+kdDebug()<<k_funcinfo<<endl;
+}
+
+int ArtsControlApplet::widthForHeight( int h ) const {
+kdDebug()<<"ArtsControlApplet::widthForHeight( int "<<h<<" )"<<endl;
+ return p->layout->sizeHint().width();
+}
+
+int ArtsControlApplet::heightForWidth( int w ) const {
+kdDebug()<<"ArtsControlApplet::heightForWidth( int "<<w<<" )"<<endl;
+ return p->layout->sizeHint().height();
+}
+
+void ArtsControlApplet::resizeEvent( QResizeEvent * /*_Event*/ ) {
+ kdDebug()<<"ArtsControlApplet::resizeEvent( QResizeEvent * )"<<endl;
+}
+
+void ArtsControlApplet::mousePressEvent( QMouseEvent* ev ) {
+ //kdDebug()<<"ArtsControlApplet::mousePressEvent( QMouseEvent* "<<ev<<" )"<<endl;
+ if ( Qt::RightButton == ev->button() /*|| Qt::LeftButton == ev->button()*/ )
+ p->menu->exec( QCursor::pos() );
+}
+
+void ArtsControlApplet::positionChange( Position ) {
+ kdDebug() << k_funcinfo << endl;
+ resetLayout();
+}
+
+void ArtsControlApplet::resetLayout() {
+kdDebug()<<k_funcinfo<<" position()="<<position()<<endl;
+ switch ( position() )
+ {
+ case pTop:
+ case pBottom:
+ p->layout->setDirection( QBoxLayout::LeftToRight );
+ if ( p->barts ) p->vu.direction( Arts::LeftToRight );
+ break;
+ case pRight:
+ case pLeft:
+ p->layout->setDirection( QBoxLayout::TopToBottom );
+ if ( p->barts ) p->vu.direction( Arts::TopToBottom );
+ break;
+ default: break;
+ }
+}
+
+void ArtsControlAppletPrivate::SVinline() {
+kdDebug() << k_funcinfo << endl;
+ if ( !svinline ) {
+ svinline = new FFTScopeView( arts->server(), _parent );
+ svinline->setMargin( 2 ); svinline->setLineWidth( 2 ); svinline->setFrameStyle( QFrame::Panel|QFrame::Sunken );
+ connect( svinline, SIGNAL( closed() ), this, SLOT( SVinline() ) );
+ layout->addWidget( svinline );
+ } else {
+ delete svinline;
+ svinline = 0;
+ }
+ _parent->supdatelayout();
+}
+
+void ArtsControlAppletPrivate::moreBars() { vu.left().count( vu.left().count()+10 ); vu.right().count( vu.right().count()+10 ); }
+void ArtsControlAppletPrivate::lessBars() { vu.left().count( vu.left().count()-10 ); vu.right().count( vu.right().count()-10 ); }
+
+void ArtsControlAppletPrivate::styleNormalBars() { vu.left().style( Arts::lmNormalBars ); vu.right().style( Arts::lmNormalBars ); _parent->supdatelayout(); }
+void ArtsControlAppletPrivate::styleFireBars() { vu.left().style( Arts::lmFireBars ); vu.right().style( Arts::lmFireBars ); _parent->supdatelayout(); }
+void ArtsControlAppletPrivate::styleLineBars() { vu.left().style( Arts::lmLineBars ); vu.right().style( Arts::lmLineBars ); _parent->supdatelayout(); }
+void ArtsControlAppletPrivate::styleLEDs() { vu.left().style( Arts::lmLEDs ); vu.right().style( Arts::lmLEDs ); _parent->supdatelayout(); }
+void ArtsControlAppletPrivate::styleAnalog() { vu.left().style( Arts::lmAnalog ); vu.right().style( Arts::lmAnalog ); _parent->supdatelayout(); }
+void ArtsControlAppletPrivate::styleSmall() { vu.left().style( Arts::lmSmall ); vu.right().style( Arts::lmSmall ); _parent->supdatelayout(); }
+
+// vim: sw=4 ts=4
+#include "artscontrolapplet.moc"
+#include "artscontrolapplet_private.moc"
diff --git a/arts/tools/artscontrolapplet.desktop b/arts/tools/artscontrolapplet.desktop
new file mode 100644
index 00000000..d43517f7
--- /dev/null
+++ b/arts/tools/artscontrolapplet.desktop
@@ -0,0 +1,109 @@
+[Desktop Entry]
+Type=Plugin
+Comment=Control the aRts sound server
+Comment[ar]=تحكّم بخادم الصوت aRts
+Comment[bg]=Управление на аудио сървъра aRts
+Comment[bn]=আর্ট্‌স্ সাউন্ড সার্ভার নিয়ন্ত্রণ করুন
+Comment[br]=A ren servijer klevet aRts
+Comment[bs]=Kontrolišite aRts server zvuka
+Comment[ca]=Control del servidor de so aRts
+Comment[cs]=Ovládání zvukového serveru aRts
+Comment[da]=Kontrollér aRts-lydserveren
+Comment[de]=Kontrolle über den aRts-Soundserver
+Comment[el]=Διαχείριση του εξυπηρετητή ήχου aRts
+Comment[eo]=Stiru la aRts-sonservilon
+Comment[es]=Controla el servidor de sonido aRts
+Comment[et]=aRts heliserveri juhtimine
+Comment[eu]=Kontrolatu aRts soinu-zerbitzaria
+Comment[fa]=کنترل کارساز صدای aRts
+Comment[fi]=Hallitse aRts-äänipalvelinta
+Comment[fr]=Contrôlez le serveur de son aRts
+Comment[ga]=Rialaigh freastalaí fuaime aRts
+Comment[gl]=Controla o servidor de son aRts
+Comment[he]=שליטה בשרת הצליל של aRts
+Comment[hu]=Az aRts hangszolgáltatás kezelése
+Comment[is]=Stjórnaðu aRts hljóðþjóninum
+Comment[it]=Controlla il server sonoro aRts
+Comment[ja]=aRts サウンドサーバを制御
+Comment[kk]=aRts дыбыс серверін басқару
+Comment[km]=បញ្ជា​ម៉ាស៊ីន​បម្រើ​សំឡេង aRts
+Comment[ko]=aRts 소리 서버를 조정합니다
+Comment[lt]=Valdyti aRts garsų serverį
+Comment[mk]=Го контролира звучниот сервер aRts
+Comment[nb]=Styr lydtjeneren aRts
+Comment[nds]=aRts-Klangserverkuntrull
+Comment[ne]=aRts ध्वनि सर्भर नियन्त्रण गर्नुहोस्
+Comment[nl]=Bedien de aRts geluidsserver
+Comment[nn]=Styr aRts-lydtenaren
+Comment[pl]=Sterowanie serwerem dźwięku aRts
+Comment[pt]=Controlar o servidor de som aRts
+Comment[pt_BR]=Controlar o servidor de som aRTs
+Comment[ru]=Управление звуковым сервером aRts
+Comment[sk]=Ovládanie zvukového servera aRts
+Comment[sl]=Nadzorujte zvočni strežnik aRts
+Comment[sr]=Контролише aRts звучни сервер
+Comment[sr@Latn]=Kontroliše aRts zvučni server
+Comment[sv]=Styr ljudservern aRts
+Comment[th]=ควบคุมเซิร์ฟเวอร์เสียง aRTs
+Comment[tr]=Arts ses sunucusunu konrtol edin
+Comment[uk]=Керує звуковим сервером aRts
+Comment[zh_CN]=控制 aRts 声音服务器
+Comment[zh_HK]=控制 aRts 聲音伺服器
+Comment[zh_TW]=控制 aRts 聲音伺服器
+Name=aRts Control
+Name[ar]=التحكم بـ aRts
+Name[bn]=আর্ট্‌স নিয়ন্ত্রণ
+Name[br]=Renadur aRts
+Name[bs]=aRts kontrola
+Name[ca]=Control d'aRts
+Name[cs]=Ovládání programu aRts
+Name[cy]=Rheoli aRts
+Name[da]=aRts-kontrol
+Name[de]=aRts-Steuerung
+Name[el]=Έλεγχος aRts
+Name[eo]=aRts-stirilo
+Name[es]=Control de aRts
+Name[et]=aRtsi juhtimine
+Name[eu]=aRts-en kontrola
+Name[fa]=کنترل aRts
+Name[fi]=aRts-hallinta
+Name[ga]=Rialú aRts
+Name[gl]=Control do aRts
+Name[hi]=एआरटीएस नियंत्रण
+Name[hu]=aRts vezérlő
+Name[is]=Stjórnborð aRts
+Name[it]=Controllo di aRts
+Name[ja]=aRts コントロール
+Name[kk]=aRts басқару құралы
+Name[km]=ឧបករណ៍​បញ្ជា aRts
+Name[ko]=aRts 설정
+Name[lt]=aRts valdymas
+Name[mk]=Контрола на aRts
+Name[nb]=aRts-kontrollverktøy
+Name[nds]=aRts-Kuntrull
+Name[ne]=aRts नियन्त्रण
+Name[nl]=aRts bediening
+Name[nn]=aRts-kontroll
+Name[pa]=aRts ਕੰਟਰੋਲ
+Name[pl]=Sterowanie aRts
+Name[pt]=Controlo do aRts
+Name[pt_BR]=Controle do aRts
+Name[ro]=Control aRts
+Name[ru]=Утилита управления aRts
+Name[sk]=Ovládanie aRts
+Name[sl]=Nadzor aRts
+Name[sr]=Контрола aRts-а
+Name[sr@Latn]=Kontrola aRts-a
+Name[sv]=Arts-kontroll
+Name[ta]=aRts கட்டுப்பாடு
+Name[tg]=aRts Идоракунӣ
+Name[tr]=aRts Kontrol
+Name[uk]=Керування aRts
+Name[uz]=aRts boshqaruvi
+Name[uz@cyrillic]=aRts бошқаруви
+Name[zh_CN]=aRts 控制
+Name[zh_HK]=aRts 控制器
+Name[zh_TW]=aRts 控制
+X-KDE-Library=libartscontrolapplet
+Icon=artscontrol
+OnlyShowIn=KDE;
diff --git a/arts/tools/artscontrolapplet.h b/arts/tools/artscontrolapplet.h
new file mode 100644
index 00000000..09ff15fe
--- /dev/null
+++ b/arts/tools/artscontrolapplet.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+ artscontrolapplet.h - description
+ -------------------
+ begin : Don Jan 30 20:42:53 CET 2003
+ copyright : (C) 2003 by Arnold Krille
+ email : arnold@arnoldarts.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef ARTSCONTROLAPPLET_H
+#define ARTSCONTROLAPPLET_H
+
+#ifdef HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
+#include <kpanelapplet.h>
+#include <qstring.h>
+#include <kconfig.h>
+
+class ArtsControlAppletPrivate;
+
+class ArtsControlApplet : public KPanelApplet
+{
+ Q_OBJECT
+public:
+ /**
+ * Construct a @ref KPanelApplet just like any other widget.
+ *
+ * @param configFile The configFile handed over in the factory function.
+ * @param Type The applet @ref type().
+ * @param actions Standard RMB menu actions supported by the applet (see @ref action() ).
+ * @param parent The pointer to the parent widget handed over in the factory function.
+ * @param name A Qt object name for your applet.
+ **/
+ ArtsControlApplet(const QString& configFile, Type t = Normal, int = 0,
+ QWidget * = 0, const char * = 0);
+ /** destructor */
+ ~ArtsControlApplet();
+ /**
+ * Retrieve a suggested width for a given height.
+ *
+ * Every applet should reimplement this function.
+ *
+ * Depending on the panel orientation the height (horizontal panel) or the
+ * width (vertical panel) of the applets is fixed.
+ * The exact values of the fixed size component depend on the panel size.
+ *
+ * On a horizontal panel the applet height is fixed, the panel will
+ * call @ref widthForHeight(int height) with @p height
+ * equal to 'the fixed applet height'
+ * when laying out the applets.
+ *
+ * The applet can now choose the other size component (width)
+ * based on the given height.
+ *
+ * The width you return is granted.
+ **/
+ int widthForHeight( int ) const;
+ /**
+ * @return A suggested height for a given width.
+ *
+ * Every applet should reimplement this function.
+ *
+ * Depending on the panel orientation the height (horizontal panel) or the
+ * width (vertical panel) of the applets is fixed.
+ * The exact values of the fixed size component depend on the panel size.
+ *
+ * On a vertical panel the applet width is fixed, the panel will
+ * call @ref heightForWidth(int width) with @p width
+ * equal to 'the fixed applet width'
+ * when laying out the applets.
+ *
+ * The applet can now choose the other size component (height)
+ * based on the given width.
+ *
+ * The height you return is granted.
+ **/
+ int heightForWidth( int ) const;
+ /**
+ * Is called when the user selects "About" from the applets RMB menu.
+ * Reimplement this function to launch a about dialog.
+ *
+ * Note that this is called only when your applet supports the About action.
+ * See @ref Action and @ref KPanelApplet().
+ **/
+ void about();
+ /**
+ * Is called when the user selects "Help" from the applets RMB menu.
+ * Reimplement this function to launch a manual or help page.
+ *
+ * Note that this is called only when your applet supports the Help action.
+ * See @ref Action and @ref KPanelApplet().
+ **/
+ void help();
+ /**
+ * Is called when the user selects "Preferences" from the applets RMB menu.
+ * Reimplement this function to launch a preferences dialog or kcontrol module.
+ *
+ * Note that this is called only when your applet supports the preferences action.
+ * See @ref Action and @ref KPanelApplet().
+ **/
+ void preferences();
+
+protected:
+
+ void resizeEvent( QResizeEvent* );
+
+ virtual void mousePressEvent( QMouseEvent* );
+
+ void positionChange( Position );
+
+public slots:
+ void supdatelayout() { emit updateLayout(); }
+
+protected slots:
+ void resetLayout();
+
+private:
+ KConfig *ksConfig;
+ ArtsControlAppletPrivate *p;
+};
+
+#endif
diff --git a/arts/tools/artscontrolapplet_private.h b/arts/tools/artscontrolapplet_private.h
new file mode 100644
index 00000000..044a156b
--- /dev/null
+++ b/arts/tools/artscontrolapplet_private.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+ artscontrolapplet_private.h - description
+ -------------------
+ begin : Don Jan 30 2003
+ copyright : (C) 2003 by Arnold Krille
+ email : arnold@arnoldarts.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef ARTSCONTROLAPPLET_PRIVATE_H
+#define ARTSCONTROLAPPLET_PRIVATE_H
+
+#include "artscontrolapplet.h"
+
+#include <qobject.h>
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qslider.h>
+#include <qpushbutton.h>
+#include <kpopupmenu.h>
+#include <kaction.h>
+#include <qfont.h>
+
+#include <kartsserver.h>
+#include <kartsdispatcher.h>
+#include <kartsfloatwatch.h>
+#include <kartswidget.h>
+#include <artsflow.h>
+#include <connect.h>
+#include <artsmoduleseffects.h>
+#include <kdelibs_export.h>
+
+#include "artsactions.h"
+
+#include "fftscopeview.h"
+
+class VolumeSlider;
+
+class KDE_EXPORT ArtsControlAppletPrivate : public QObject {
+ Q_OBJECT
+private:
+ ArtsControlApplet *_parent;
+ ArtsActions* _artsactions;
+public:
+ QBoxLayout *layout;
+ KArtsServer *arts;
+ KArtsDispatcher *dispatcher;
+ Arts::StereoVolumeControl volume;
+ bool barts, bInUpdate;
+ FFTScopeView *svinline;
+
+ KArtsWidget *vuw;
+ Arts::StereoVolumeControlGui vu;
+
+ KPopupMenu *menu;
+ KAction *_showSV, *_showSVinline, *_showAM, *_showArtsStatus, *_showMidiManager, *_showEnvironment, *_showMediaTypes, *_moreBars, *_lessBars;
+ KAction *_styleNormalBars, *_styleFireBars, *_styleLineBars, *_styleLEDs, *_styleAnalog, *_styleSmall;
+
+ ArtsControlAppletPrivate( ArtsControlApplet *parent )
+ : QObject(parent)
+ , _parent( parent )
+ , barts( false )
+ , bInUpdate( false )
+ {
+ arts = new KArtsServer( 0 );
+ dispatcher = new KArtsDispatcher( 0 );
+ if( ! arts->server().isNull() ) barts = true;
+ if( barts ) volume = arts->server().outVolume();
+ svinline=0;
+
+ _artsactions = new ArtsActions( arts, 0, parent );
+
+ menu = new KPopupMenu( 0 );
+ _showSV = _artsactions->actionScopeView();
+ _showSV->plug( menu );
+ _showSVinline = new KAction( i18n( "Toggle &Inline FFT Scope" ), "artscontrol", KShortcut(), this, SLOT( SVinline() ), this );
+ _showSVinline->plug( menu );
+ _showAM = _artsactions->actionAudioManager();
+ _showAM->plug( menu );
+ _showArtsStatus = _artsactions->actionArtsStatusView();
+ _showArtsStatus->plug( menu );
+ _showMidiManager = _artsactions->actionMidiManagerView();
+ _showMidiManager->plug( menu );
+ _showEnvironment = _artsactions->actionEnvironmentView();
+ _showEnvironment->plug( menu );
+ _showMediaTypes = _artsactions->actionMediaTypesView();
+ _showMediaTypes->plug( menu );
+ menu->insertSeparator();
+ menu->insertItem( i18n( "VU-Style" ), _artsactions->stylemenu() );
+ connect( _artsactions, SIGNAL( styleNormal() ), this, SLOT( styleNormalBars() ) );
+ connect( _artsactions, SIGNAL( styleFire() ), this, SLOT( styleFireBars() ) );
+ connect( _artsactions, SIGNAL( styleLine() ), this, SLOT( styleLineBars() ) );
+ connect( _artsactions, SIGNAL( styleLED() ), this, SLOT( styleLEDs() ) );
+ connect( _artsactions, SIGNAL( styleAnalog() ), this, SLOT( styleAnalog() ) );
+ connect( _artsactions, SIGNAL( styleSmall() ), this, SLOT( styleSmall() ) );
+ }
+ ~ArtsControlAppletPrivate() {
+ if ( svinline ) SVinline();
+ }
+public slots:
+ void SVinline(); // ScopeView inline
+ void moreBars();
+ void lessBars();
+ void styleNormalBars();
+ void styleFireBars();
+ void styleLineBars();
+ void styleLEDs();
+ void styleAnalog();
+ void styleSmall();
+};
+
+// vim: sw=4 ts=4
+#endif
diff --git a/arts/tools/artsmidimanagerview.rc b/arts/tools/artsmidimanagerview.rc
new file mode 100644
index 00000000..6bd743e6
--- /dev/null
+++ b/arts/tools/artsmidimanagerview.rc
@@ -0,0 +1,9 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="artsmidimanager.rc" version="1">
+<MenuBar>
+ <Menu name="add"><text>&amp;Add</text>
+ <Action name="add_oss_midi_port"/>
+ <Action name="add_arts_midi_output"/>
+ </Menu>
+</MenuBar>
+</kpartgui>
diff --git a/arts/tools/audiomanager.cpp b/arts/tools/audiomanager.cpp
new file mode 100644
index 00000000..d250e37f
--- /dev/null
+++ b/arts/tools/audiomanager.cpp
@@ -0,0 +1,198 @@
+/*
+
+ Copyright (C) 1999 Stefan Westerfeld
+ stefan@space.twc.de
+ 2003 Arnold Krille
+ arnold@arnoldarts.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 "audiomanager.h"
+#include "choosebusdlg.h"
+
+#include <qtimer.h>
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <klistview.h>
+#include <kiconloader.h>
+
+using namespace std;
+
+/*
+ * as this is an 1:1 port of an old arts-0.3.4.1 artsbuilable visual widget,
+ * you'll see some porting artefacts, and it's not elegance itself ;)
+ */
+Gui_AUDIO_MANAGER::Gui_AUDIO_MANAGER( QWidget* parent, const char* name ) : Template_ArtsView( parent,name )
+{
+ this->setCaption( i18n( "Audio Manager" ) );
+ this->setIcon( MainBarIcon( "artsaudiomanager", 32 ) );
+ //printf("constructor\n");
+ ParentWidget = 0;
+ listview = 0;
+ inDialog = false;
+ proxy = new GuiAudioManagerProxy(this);
+
+ AudioManager = Arts::Reference("global:Arts_AudioManager");
+ changes = AudioManager.changes()-1;
+ setParent(this,0);
+ tick();
+ show();
+
+ QTimer *updatetimer = new QTimer(this);
+ updatetimer->start(500);
+ QObject::connect(updatetimer,SIGNAL(timeout()),this,SLOT(tick()));
+}
+
+Gui_AUDIO_MANAGER::~Gui_AUDIO_MANAGER()
+{
+ if(listview) delete listview;
+ delete proxy;
+}
+
+#if 0
+void Gui_AUDIO_MANAGER::widgetDestroyed(QWidget *widget)
+{
+ assert(widget == listview);
+ listview = 0;
+}
+#endif
+
+void Gui_AUDIO_MANAGER::setParent(QWidget *parent, QBoxLayout * /*layout*/)
+{
+/************************************************************************
+ * From Gui_INSTRUMENT_MAPPER:
+ *
+ * I am still not sure wether this kind of putting yourself into a parent
+ * widget (with own layout etc.) is a good idea (there may not even be
+ * a singe call to setParent, because there is no parent).
+ *
+ * But the "how to write aRts widgets"-stuff will need some experiments,
+ * so lets try that method...
+ *
+ * ----
+ *
+ * But perhaps here (since only one widget Listview is used) something
+ * else would be appropriate. Check that. FIXME
+ ************************************************************************/
+
+ QVBoxLayout *mainlayout = new QVBoxLayout(parent);
+ /*QHBoxLayout *contentslayout = new QHBoxLayout;*/
+
+// list
+
+ listview = new KListView(parent);
+
+ listview->addColumn(i18n("Title"),175);
+ listview->addColumn(i18n("Type"),50);
+ listview->addColumn(i18n("Bus"),75);
+
+ listview->setMinimumSize(300,100);
+
+ QObject::connect(listview,SIGNAL(executed(QListViewItem *)),proxy,
+ SLOT(edit(QListViewItem *)));
+
+ mainlayout->addWidget(listview);
+
+ mainlayout->activate();
+ //mainlayout->freeze();
+ ParentWidget = parent;
+}
+
+void Gui_AUDIO_MANAGER::tick()
+{
+ unsigned long newChanges = AudioManager.changes();
+ if(inDialog) return;
+ if(changes == newChanges) return;
+
+ changes = newChanges;
+
+ listview->clear();
+ vector<Arts::AudioManagerInfo> *acs = AudioManager.clients();
+
+ unsigned long c;
+ for(c=0;c<acs->size();c++)
+ {
+ //char status[2][10] = {"init","running"};
+ QString description = QString::fromUtf8( (*acs)[c].title.c_str() );
+ QString type;
+ if((*acs)[c].direction == Arts::amPlay)
+ type = i18n("play");
+ else
+ type = i18n("record");
+ QString destination = QString::fromUtf8( (*acs)[c].destination.c_str() );
+ long ID = (*acs)[c].ID;
+
+ (void)new AudioManagerItem(listview, description, type, destination, ID);
+ }
+ delete acs;
+ //Widget->show();
+}
+
+void Gui_AUDIO_MANAGER::edit(QListViewItem *item)
+{
+ AudioManagerItem *ai = (AudioManagerItem *)item;
+ ChooseBusDlg *cd = new ChooseBusDlg(0);
+ assert(cd);
+
+ inDialog = true;
+ int accept = cd->exec();
+ inDialog = false;
+
+ if( accept == QDialog::Accepted )
+ {
+ QString result = cd->result();
+ if(!result.isNull())
+ {
+ //lukas: I hope UTF-8 is OK here...
+ AudioManager.setDestination(ai->ID(),result.utf8().data());
+ // refresh:
+ changes = 0;
+ tick();
+ }
+ }
+ delete cd;
+}
+
+GuiAudioManagerProxy::GuiAudioManagerProxy(Gui_AUDIO_MANAGER *gim)
+{
+ this->gim = gim;
+}
+
+void GuiAudioManagerProxy::edit(QListViewItem *item)
+{
+ gim->edit(item);
+}
+
+AudioManagerItem::AudioManagerItem(QListView *parent, QString a,
+ QString b, QString c, long ID) :QListViewItem(parent,a,b,c)
+{
+ _ID = ID;
+}
+
+long AudioManagerItem::ID()
+{
+ return _ID;
+}
+
+AudioManagerItem::~AudioManagerItem()
+{
+ //
+}
+#include "audiomanager.moc"
+
+// vim: sw=4 ts=4
diff --git a/arts/tools/audiomanager.h b/arts/tools/audiomanager.h
new file mode 100644
index 00000000..202c454c
--- /dev/null
+++ b/arts/tools/audiomanager.h
@@ -0,0 +1,79 @@
+/*
+
+ Copyright (C) 1999 Stefan Westerfeld
+ stefan@space.twc.de
+ 2003 Arnold Krille
+ arnold@arnoldarts.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.
+
+ */
+
+#ifndef _AUDIOMANAGER_H_
+#define _AUDIOMANAGER_H_
+
+#include <artsflow.h>
+#include <qwidget.h>
+#include <qlistview.h>
+
+#include "templateview.h"
+
+class KListView;
+class GuiAudioManagerProxy;
+class QBoxLayout;
+
+class Gui_AUDIO_MANAGER : public Template_ArtsView
+{
+ Q_OBJECT
+protected:
+ QWidget *ParentWidget;
+ KListView *listview;
+ GuiAudioManagerProxy *proxy;
+ Arts::AudioManager AudioManager;
+
+ bool inDialog;
+ unsigned long changes;
+ int x,y;
+public:
+ Gui_AUDIO_MANAGER( QWidget* =0, const char* =0 );
+ ~Gui_AUDIO_MANAGER();
+
+ void setParent(QWidget *Parent,QBoxLayout *layout);
+
+ void edit(QListViewItem *item);
+public slots:
+ void tick();
+};
+
+class GuiAudioManagerProxy :public QObject {
+ Q_OBJECT
+ Gui_AUDIO_MANAGER *gim;
+public:
+ GuiAudioManagerProxy(Gui_AUDIO_MANAGER *gim);
+public slots:
+ void edit(QListViewItem *item);
+};
+
+class AudioManagerItem : public QListViewItem {
+ long _ID;
+public:
+ AudioManagerItem(QListView *parent, QString a, QString b,
+ QString c, long ID);
+ ~AudioManagerItem();
+
+ long ID();
+};
+
+#endif
diff --git a/arts/tools/choosebusdlg.cpp b/arts/tools/choosebusdlg.cpp
new file mode 100644
index 00000000..77e439ee
--- /dev/null
+++ b/arts/tools/choosebusdlg.cpp
@@ -0,0 +1,184 @@
+/*
+
+ Copyright (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 "choosebusdlg.h"
+
+#include <artsflow.h>
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+
+#include <kbuttonbox.h>
+#include <kseparator.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kstdguiitem.h>
+
+using namespace std;
+
+static void min_size(QWidget *w) {
+ w->setMinimumSize(w->sizeHint());
+}
+
+ChooseBusDlg::ChooseBusDlg(QWidget *parent)
+ : KDialog(parent,"X", TRUE)
+ , _newbusitemindex( -1 )
+{
+ setCaption(i18n("Choose Bus"));
+
+ QVBoxLayout *mainlayout = new QVBoxLayout(this);
+
+// caption label: "Synthesis running..."
+
+ mainlayout->addSpacing(5);
+ QLabel *captionlabel = new QLabel(this);
+ QFont labelfont(captionlabel->font());
+ labelfont.setPointSize(labelfont.pointSize()*3/2);
+ captionlabel->setFont(labelfont);
+ captionlabel->setText(QString(" ")+i18n("Available busses:")+QString(" "));
+ captionlabel->setAlignment(AlignCenter);
+ min_size(captionlabel);
+ mainlayout->addWidget(captionlabel);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler2 = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler2);
+
+ mainlayout->addSpacing(5);
+
+// listwidget
+
+
+ listbox = new QListBox(this);
+ listbox->setMinimumSize(300,200);
+
+ Arts::AudioManager aman = Arts::Reference("global:Arts_AudioManager");
+
+ if(!aman.isNull())
+ {
+ vector<string> *destinations = aman.destinations();
+ unsigned long i;
+ for(i=0;i<destinations->size();i++)
+ listbox->insertItem((*destinations)[i].c_str());
+ delete destinations;
+ }
+ if( listbox->count() > 0 )
+ listbox->setCurrentItem( 0 );
+
+ mainlayout->addWidget(listbox);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler);
+ mainlayout->addSpacing(5);
+
+// new bus lineedit
+
+ QBoxLayout * layout2 = new QHBoxLayout( mainlayout );
+ //mainlayout->addLayout( layout2 );
+ QLabel * newbuslabel = new QLabel( i18n( "New bus:" ), this );
+ layout2->addWidget( newbuslabel );
+ lineedit = new KLineEdit( this );
+ connect( lineedit, SIGNAL( textChanged( const QString & ) ), SLOT( textChanged( const QString & ) ) );
+ layout2->addWidget( lineedit );
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler3 = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler3);
+
+ mainlayout->addSpacing(5);
+
+// buttons
+
+ mainlayout->addSpacing(5);
+ QHBoxLayout *buttonlayout = new QHBoxLayout( mainlayout );
+ //mainlayout->addLayout(buttonlayout);
+ mainlayout->addSpacing(5);
+
+ buttonlayout->addSpacing(5);
+ KButtonBox *bbox = new KButtonBox(this);
+
+ bbox->addButton(KStdGuiItem::help(), this, SLOT( help() ));
+ bbox->addStretch(1);
+
+ QPushButton * okbutton = bbox->addButton(KStdGuiItem::ok());
+ okbutton->setDefault( true );
+ connect( okbutton, SIGNAL( clicked() ), SLOT(accept() ) );
+
+ QButton *cancelbutton = bbox->addButton(KStdGuiItem::cancel());
+ connect( cancelbutton, SIGNAL( clicked() ), SLOT(reject() ) );
+
+ bbox->layout();
+
+ buttonlayout->addWidget(bbox);
+ buttonlayout->addSpacing(5);
+
+ mainlayout->freeze();
+}
+
+QString ChooseBusDlg::result()
+{
+ if(listbox->currentItem() != -1)
+ {
+ return(listbox->text(listbox->currentItem()));
+ }
+ return(0);
+}
+
+void ChooseBusDlg::help()
+{
+ KApplication::kApplication()->invokeHelp("", "artsbuilder");
+}
+
+void ChooseBusDlg::textChanged( const QString & busname )
+{
+ if( ! busname.isEmpty() )
+ {
+ if( _newbusitemindex > -1 )
+ listbox->changeItem( busname, _newbusitemindex );
+ else
+ {
+ _newbusitemindex = listbox->count();
+ listbox->insertItem( busname, _newbusitemindex );
+ listbox->setCurrentItem( _newbusitemindex );
+ }
+ }
+ else
+ {
+ listbox->removeItem( _newbusitemindex );
+ listbox->setCurrentItem( _newbusitemindex - 1 );
+ _newbusitemindex = -1;
+ }
+}
+
+#include "choosebusdlg.moc"
+
+// vim: sw=4 ts=4
diff --git a/arts/tools/choosebusdlg.h b/arts/tools/choosebusdlg.h
new file mode 100644
index 00000000..40c48603
--- /dev/null
+++ b/arts/tools/choosebusdlg.h
@@ -0,0 +1,49 @@
+/*
+
+ Copyright (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.
+
+ */
+
+#ifndef __CHOOSEBUSDLG_H_
+#define __CHOOSEBUSDLG_H_
+
+#include <kdialog.h>
+
+class QListBox;
+class KLineEdit;
+class QPushButton;
+
+class ChooseBusDlg :public KDialog {
+ Q_OBJECT
+ QListBox *listbox;
+ KLineEdit * lineedit;
+
+ int _newbusitemindex;
+public:
+ ChooseBusDlg(QWidget *parent);
+
+public slots:
+ QString result();
+ void help();
+
+protected slots:
+ void textChanged( const QString & );
+};
+#endif
+
+// vim: sw=4 ts=4
diff --git a/arts/tools/environmentview.cpp b/arts/tools/environmentview.cpp
new file mode 100644
index 00000000..e2074b5f
--- /dev/null
+++ b/arts/tools/environmentview.cpp
@@ -0,0 +1,171 @@
+/*
+
+ Copyright (C) 2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Matthias Kretz <kretz@kde.org>
+ 2003 Arnold Krille <arnold@arnoldarts.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 "environmentview.h"
+#include <qdir.h>
+#include <qfile.h>
+#include <qpushbutton.h>
+
+#include <klistbox.h>
+#include <kartswidget.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <stdio.h>
+#include <fstream>
+#include <vector>
+
+#include <qlayout.h>
+
+#define DEFAULT_ENV_FILENAME "~/default.arts-env"
+
+using namespace Arts;
+using Environment::Container;
+using Environment::Item;
+
+class ItemView : public QListBoxText {
+public:
+ Item item;
+ KArtsWidget *widget;
+ ItemView(QListBox *listBox, Item item)
+ : QListBoxText(listBox), item(item), widget(0)
+ {
+ }
+ ~ItemView()
+ {
+ delete widget;
+ widget = 0;
+ printf("~ItemView()\n");
+ }
+ QString text() const {
+ return QString::fromLatin1(item._interfaceName().c_str());
+ }
+};
+
+EnvironmentView::EnvironmentView( Container container, QWidget* parent, const char* name ) : Template_ArtsView( parent,name ), container(container)
+{
+ this->setCaption( i18n( "Environment" ) );
+ this->setIcon( MainBarIcon( "artsenvironment", 32 ) );
+ QVBoxLayout* _layout = new QVBoxLayout( this );
+ _layout->setAutoAdd( true );
+ defaultEnvFileName = DEFAULT_ENV_FILENAME;
+ defaultEnvFileName.replace('~', QDir::homeDirPath());
+ listBox = new KListBox(this);
+ update();
+ connect(listBox,SIGNAL(executed(QListBoxItem*)),
+ this,SLOT(view(QListBoxItem*)));
+
+ QPushButton *mixerButton = new QPushButton(i18n("Add Mixer"), this);
+ connect(mixerButton, SIGNAL(clicked()), this, SLOT(addMixer()));
+
+ QPushButton *effectRackButton = new QPushButton(i18n("Add Effect Rack"), this);
+ connect(effectRackButton, SIGNAL(clicked()), this, SLOT(addEffectRack()));
+
+ QPushButton *delButton = new QPushButton(i18n("Delete Item"), this);
+ connect(delButton, SIGNAL(clicked()), this, SLOT(delItem()));
+
+ QPushButton *loadButton = new
+ QPushButton(i18n("Load %1").arg(DEFAULT_ENV_FILENAME), this);
+ connect(loadButton, SIGNAL(clicked()), this, SLOT(load()));
+
+ QPushButton *saveButton = new
+ QPushButton(i18n("Save %1").arg(DEFAULT_ENV_FILENAME), this);
+ connect(saveButton, SIGNAL(clicked()), this, SLOT(save()));
+ show();
+}
+
+void EnvironmentView::view(QListBoxItem *i)
+{
+ ItemView *iv = static_cast<ItemView*>(i);
+
+ if(!iv->widget)
+ {
+ GenericGuiFactory gf;
+ Widget w = gf.createGui(iv->item);
+ if(!w.isNull())
+ {
+ iv->widget = new KArtsWidget(w);
+ }
+ else
+ {
+ printf("no gui for %s\n",iv->text().ascii());
+ }
+ }
+ if(iv->widget)
+ iv->widget->show();
+}
+
+void EnvironmentView::addMixer()
+{
+ container.createItem("Arts::Environment::MixerItem");
+ update();
+}
+
+void EnvironmentView::addEffectRack()
+{
+ container.createItem("Arts::Environment::EffectRackItem");
+ update();
+}
+
+void EnvironmentView::delItem()
+{
+ int i = listBox->currentItem();
+ if(i < 0) return; /* nothing selected */
+
+ ItemView *iv = static_cast<ItemView*>(listBox->item(i));
+ container.removeItem(iv->item);
+ update();
+}
+
+void EnvironmentView::update()
+{
+ listBox->clear();
+
+ std::vector<Item> *items = container.items();
+ for(std::vector<Item>::iterator i = items->begin(); i != items->end(); i++)
+ (void)new ItemView(listBox, *i);
+ delete items;
+}
+
+void EnvironmentView::load()
+{
+ std::ifstream infile(QFile::encodeName(defaultEnvFileName).data());
+ std::string line;
+ std::vector<std::string> strseq;
+
+ while(getline(infile,line))
+ strseq.push_back(line);
+
+ defaultEnvironment().loadFromList(strseq);
+}
+
+void EnvironmentView::save()
+{
+ std::vector<std::string> *strseq;
+ strseq = defaultEnvironment().saveToList();
+
+ std::ofstream outfile(QFile::encodeName(defaultEnvFileName).data());
+ for(std::vector<std::string>::iterator i = strseq->begin(); i != strseq->end(); i++)
+ outfile << ( *i ) << std::endl;
+ delete strseq;
+}
+#include "environmentview.moc"
diff --git a/arts/tools/environmentview.h b/arts/tools/environmentview.h
new file mode 100644
index 00000000..535fcc98
--- /dev/null
+++ b/arts/tools/environmentview.h
@@ -0,0 +1,57 @@
+ /*
+
+ Copyright (C) 2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Matthias Kretz <kretz@kde.org>
+ 2003 Arnold Krille <arnold@arnoldarts.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.
+
+ */
+
+#ifndef ARTS_ENVIRONMENT_VIEW_H
+#define ARTS_ENVIRONMENT_VIEW_H
+
+#include "artsmodules.h"
+
+#include "templateview.h"
+
+class QListBoxItem;
+class KListBox;
+
+class EnvironmentView : public Template_ArtsView {
+ Q_OBJECT
+protected:
+ Arts::Environment::Container container;
+ KListBox *listBox;
+ QString defaultEnvFileName;
+
+public:
+ EnvironmentView( Arts::Environment::Container container, QWidget* =0, const char* =0 );
+
+public slots:
+ void view(QListBoxItem *i);
+ void addMixer();
+ void addEffectRack();
+ void delItem();
+ void update();
+ void load();
+ void save();
+
+};
+
+Arts::Environment::Container defaultEnvironment();
+
+#endif /* ARTS_ENVIRONMENT_VIEW_H */
diff --git a/arts/tools/fftscopeview.cpp b/arts/tools/fftscopeview.cpp
new file mode 100644
index 00000000..cb4c2acc
--- /dev/null
+++ b/arts/tools/fftscopeview.cpp
@@ -0,0 +1,163 @@
+/*
+
+ Copyright ( C ) 2000-2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Arnold Krille <arnold@arnoldarts.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 "fftscopeview.h"
+
+#include <qlayout.h>
+#include <qcursor.h>
+#include <qtimer.h>
+#include <kaction.h>
+#include <kpopupmenu.h>
+#include <kartswidget.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kiconloader.h>
+
+#include "artsactions.h"
+
+using namespace std;
+using namespace Arts;
+
+FFTScopeView::FFTScopeView( SimpleSoundServer server, QWidget* parent )
+ : Template_ArtsView( parent )
+ , server( server )
+ , scopeData( 0 )
+{
+kdDebug()<<k_funcinfo<<endl;
+ this->setCaption( i18n( "FFT Scope View" ) );
+ this->setIcon( MainBarIcon( "artsfftscope", 32 ) );
+ /*
+ create a stereo fft scope on the server and push it into the
+ effect chain
+ */
+ {
+ scopefx = DynamicCast( server.createObject( "Arts::StereoFFTScope" ) );
+ assert( !scopefx.isNull() );
+ scopefx.start();
+
+ // put it into the effect chain
+ effectID = server.outstack().insertBottom( scopefx,"FFT Scope" );
+ }
+
+ updateScopeData();
+ QBoxLayout * l = new QHBoxLayout( this );
+ l->setAutoAdd( TRUE );
+
+ for ( unsigned int i=0;i<scopeData->size();i++ )
+ {
+ LevelMeter tmp;
+ tmp.count( 20 );
+ scopeScales.push_back( tmp );
+ scopeDraw.push_back( 0.0 );
+ KArtsWidget *w = new KArtsWidget( tmp, this );
+ aw.push_back( w );
+ }
+
+ l->activate();
+ show();
+
+ updatetimer = new QTimer( this );
+ updatetimer->start( 100 );
+ connect( updatetimer,SIGNAL( timeout() ),this,SLOT( updateScope() ) );
+
+ _artsactions = new ArtsActions( 0, 0, this );
+ _moreBars = ArtsActions::actionMoreBars( this, SLOT( moreBars() ), 0 );
+ _lessBars = ArtsActions::actionLessBars( this, SLOT( lessBars() ), 0 );
+ _menu = new KPopupMenu( 0 );
+ _moreBars->plug( _menu ); _lessBars->plug( _menu );
+ _substyle = new KAction( i18n( "Substyle" ), "", KShortcut(), this, SLOT( substyle() ), this );
+ _substyle->plug( _menu );
+ _menu->insertItem( i18n("VU-Style"), _artsactions->stylemenu() );
+
+ connect( _artsactions, SIGNAL( styleNormal() ), this, SLOT( styleNormalBars() ) );
+ connect( _artsactions, SIGNAL( styleFire() ), this, SLOT( styleFireBars() ) );
+ connect( _artsactions, SIGNAL( styleLine() ), this, SLOT( styleLineBars() ) );
+ connect( _artsactions, SIGNAL( styleLED() ), this, SLOT( styleLEDs() ) );
+ connect( _artsactions, SIGNAL( styleAnalog() ), this, SLOT( styleAnalog() ) );
+ connect( _artsactions, SIGNAL( styleSmall() ), this, SLOT( styleSmall() ) );
+}
+
+FFTScopeView::~FFTScopeView() {
+kdDebug()<<"FFTScopeView::~FFTScopeView()"<<endl;
+ updatetimer->stop();
+ for ( int i=int( aw.size() )-1; i>=0; i-- ) { scopeScales[ i ].hide(); delete aw[ i ]; aw.pop_back(); scopeScales.pop_back(); }
+ server.outstack().remove( effectID );
+kdDebug()<<"FFTScopeView is gone..."<<endl;
+}
+
+void FFTScopeView::updateScopeData() {
+ if ( scopeData ) delete scopeData;
+ scopeData = scopefx.scope();
+}
+
+void FFTScopeView::updateScope() {
+ updateScopeData();
+
+ for ( unsigned int i=0;i<scopeData->size();i++ )
+ {
+// scopeDraw[ i ] /= 1.25;
+// if ( ( *scopeData )[ i ] > scopeDraw[ i ] ) scopeDraw[ i ] = ( *scopeData )[ i ];
+ scopeDraw[ i ] = ( *scopeData )[ i ];
+ scopeScales[ i ].invalue( scopeDraw[ i ] );
+ }
+}
+
+void FFTScopeView::mousePressEvent( QMouseEvent* ev ) {
+ if ( Qt::RightButton == ev->button() /*|| Qt::LeftButton == ev->button()*/ )
+ _menu->exec( QCursor::pos() );
+}
+
+void FFTScopeView::moreBars() {
+ int bars = scopeScales[ 0 ].count() + 10;
+ for ( unsigned int i=0;i<scopeData->size();i++ )
+ scopeScales[ i ].count( bars );
+}
+
+void FFTScopeView::lessBars() {
+ int bars = scopeScales[ 0 ].count() - 10;
+ for ( unsigned int i=0;i<scopeData->size();i++ )
+ scopeScales[ i ].count( bars );
+}
+
+void FFTScopeView::setStyle( Arts::LevelMeterStyle style ) {
+ for ( uint i=0; i<scopeScales.size(); i++ )
+ scopeScales[ i ].style( style );
+}
+
+void FFTScopeView::styleNormalBars() { setStyle( Arts::lmNormalBars ); }
+void FFTScopeView::styleFireBars() { setStyle( Arts::lmFireBars ); }
+void FFTScopeView::styleLineBars() { setStyle( Arts::lmLineBars ); }
+void FFTScopeView::styleLEDs() { setStyle( Arts::lmLEDs ); }
+void FFTScopeView::styleAnalog() { setStyle( Arts::lmAnalog ); }
+void FFTScopeView::styleSmall() { setStyle( Arts::lmSmall ); }
+
+#include <kinputdialog.h>
+
+void FFTScopeView::substyle() {
+ int _substyle = KInputDialog::getInteger( i18n("Substyle"), i18n("Please enter substyle:"), 0, 0, 10, 1, 0, this );
+ for ( unsigned int i=0; i<scopeData->size(); i++ )
+ scopeScales[ i ].substyle( _substyle );
+}
+
+#include "fftscopeview.moc"
+// vim: sw=4 ts=4
+
diff --git a/arts/tools/fftscopeview.h b/arts/tools/fftscopeview.h
new file mode 100644
index 00000000..d01b6c3c
--- /dev/null
+++ b/arts/tools/fftscopeview.h
@@ -0,0 +1,81 @@
+/*
+
+ Copyright ( C ) 2000-2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Arnold Krille <arnold@arnoldarts.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.
+
+ */
+
+#ifndef ARTSCONTROLLIB_FFTSCOPEVIEW_H
+#define ARTSCONTROLLIB_FFTSCOPEVIEW_H
+
+#include <artsmodules.h>
+#include <flowsystem.h>
+#include <kartsserver.h>
+
+#include "templateview.h"
+
+#include <artsgui.h>
+#include <kdelibs_export.h>
+
+class QTimer;
+class KPopupMenu;
+class KAction;
+class KArtsWidget;
+class ArtsActions;
+
+class KDE_EXPORT FFTScopeView : public Template_ArtsView {
+ Q_OBJECT
+protected:
+ Arts::StereoFFTScope scopefx;
+ Arts::SimpleSoundServer server;
+ long effectID;
+
+ std::vector<float> *scopeData;
+ std::vector<float> scopeDraw;
+ std::vector<Arts::LevelMeter> scopeScales;
+ std::vector<KArtsWidget*> aw;
+ QTimer *updatetimer;
+
+ ArtsActions* _artsactions;
+ KPopupMenu *_menu, *_stylemenu;
+ KAction *_moreBars, *_lessBars;
+ KAction *_styleNormalBars, *_styleFireBars, *_styleLineBars, *_styleLEDs, *_styleAnalog, *_styleSmall;
+ KAction *_substyle;
+
+ void mousePressEvent( QMouseEvent* );
+public:
+ void updateScopeData();
+ FFTScopeView( Arts::SimpleSoundServer server, QWidget* =0 );
+ ~FFTScopeView();
+
+public slots:
+ void updateScope();
+ void moreBars();
+ void lessBars();
+ void setStyle( Arts::LevelMeterStyle style );
+ void styleNormalBars();
+ void styleFireBars();
+ void styleLineBars();
+ void styleLEDs();
+ void styleAnalog();
+ void styleSmall();
+ void substyle();
+};
+
+// vim: sw=4 ts=4
+#endif
diff --git a/arts/tools/levelmeters.cpp b/arts/tools/levelmeters.cpp
new file mode 100644
index 00000000..3b2ca1ac
--- /dev/null
+++ b/arts/tools/levelmeters.cpp
@@ -0,0 +1,239 @@
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qfontmetrics.h>
+#include <qptrlist.h>
+#include <kled.h>
+#include "levelmeters.h"
+
+const int PeakBar::peakMillis=1500;
+
+PeakBar::PeakBar(QWidget *parent)
+ : ACLevelMeter(parent)
+ , maxValue( 0.0f )
+ , minValue( 0.0f )
+{
+ clipped = false;
+ displayMinPeak= false;
+ horizontalMode= false;
+ currentValue= 0.0f;
+
+ lastValues.setAutoDelete( TRUE );
+
+ setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
+ setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
+ setBackgroundMode(NoBackground);
+ setMinimumSize(frameWidth()+7, 70);
+}
+
+void PeakBar::frameChanged() {
+ setMinimumSize(frameWidth()+7, 70);
+ QFrame::frameChanged();
+}
+
+QSize PeakBar::sizeHint() const {
+ return QSize(13, 250);
+}
+
+void PeakBar::checkMinMax() {
+ int mustRecheck= 0; // bool
+ Observation *o;
+
+ while ((o= lastValues.first()) && o->time.elapsed() > peakMillis) {
+ lastValues.removeFirst();
+ mustRecheck= 1;
+ }
+
+ if (mustRecheck) {
+ maxValue= 0.f;
+ minValue= 1.f;
+ clipped = false;
+ for (QPtrListIterator<Observation> it(lastValues); it.current(); ++it) {
+ float value= it.current()->value;
+ if (value>maxValue)
+ maxValue= value;
+ if (value<minValue)
+ minValue= value;
+ if (value > 1.f)
+ clipped = true;
+ }
+ }
+}
+
+void PeakBar::drawContents(QPainter *p)
+{
+ QRect size= contentsRect();
+
+ checkMinMax();
+
+ p->setBrush(clipped ? darkRed : darkBlue);
+ p->setPen(NoPen);
+ p->drawRect(size);
+
+ QRect bar= size;
+ p->setBrush(clipped ? red : blue);
+ if (horizontalMode) {
+ bar.setWidth((int)(bar.width()*currentValue));
+ } else {
+ int newHeight= (int)(bar.height()*currentValue);
+ bar.moveBy(0, bar.height()-newHeight);
+ bar.setHeight(newHeight);
+ }
+ p->drawRect(bar);
+
+ int y;
+ // TODO: if (horizontalMode)
+ if (displayMinPeak) {
+ y= frameWidth()+size.height()-((int)(size.height()*minValue));
+ p->setPen(white);
+ p->drawLine(frameWidth(), y, frameWidth()+size.width()-1, y);
+ }
+ y= frameWidth()+size.height()-((int)(size.height()*maxValue));
+ p->setPen(white);
+ p->drawLine(frameWidth(), y, frameWidth()+size.width()-1, y);
+}
+
+void PeakBar::setValue(float f) {
+ if (f > 1.f)
+ clipped = true;
+
+ currentValue= f;
+ if (f>=maxValue)
+ maxValue= f;
+ if (displayMinPeak && (f<=minValue))
+ minValue= f;
+
+ lastValues.append(new Observation(f));
+
+ repaint();
+}
+
+// -------------------------------------------------------------
+
+PeakLevelMeters::PeakLevelMeters(QWidget *parent):
+ StereoLevelMeter(parent), left(this), right(this), scaleView(this)
+{
+ QBoxLayout *layout= new QHBoxLayout(this);
+ layout->addWidget(&left);
+ // layout->setStretchFactor(&left, 0);
+ layout->addWidget(&right);
+ // layout->setStretchFactor(&right, 0);
+ layout->addWidget(&scaleView);
+ // layout->setStretchFactor(&scaleView, 0);
+ left.setLineWidth(2);
+ right.setLineWidth(2);
+ scaleView.setScaleMargins(right.frameWidth());
+ setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
+
+ setDbRange(36);
+}
+
+void PeakLevelMeters::setDbRange(int db) {
+ dbRange= db;
+ scaleView.setDbRange(db);
+}
+
+void PeakLevelMeters::setValues(float leftVal, float rightVal) {
+ float f= 1.0f+levelToDB(leftVal)/dbRange;
+ if (f<0.f) f= 0.f;
+ left.setValue(f);
+
+ f= 1.0f+levelToDB(rightVal)/dbRange;
+ if (f<0.f) f= 0.f;
+ right.setValue(f);
+}
+
+ScaleView::ScaleView(QWidget *parent): QFrame(parent) {
+ font.setPixelSize(10);
+ setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
+}
+
+void ScaleView::setDbRange(int db) {
+ dbRange= db;
+ repaint();
+}
+
+QSize ScaleView::sizeHint() const {
+ return QSize(QFontMetrics(font).width("-88")+8, 250);
+}
+
+void ScaleView::drawContents(QPainter *p) {
+ QRect size= contentsRect();
+ size.rTop()+= upperMargin;
+ size.rBottom()-= lowerMargin;
+
+ QFrame::drawContents(p); // clear background
+
+ int step=3;
+ while (dbRange/step*20>size.height())
+ step*=2;
+
+ /* float offset= ((float)size.height()*step)/dbRange, pos=0.f;
+ p->setPen(black);
+ p->drawLine(0, (, size.width()*3/5, y);*/
+
+ p->setPen(black);
+ p->setFont(font);
+ QString numStr;
+ for (int i=0; i<=dbRange; i++) {
+ int y= size.top()+(size.height()-1)*i/dbRange;
+ if (i%step==0) {
+ p->drawLine(0, y, 4, y);
+ numStr.setNum(-i);
+ p->drawText(8, y+5, numStr);
+ } else
+ p->drawLine(0, y, 2, y);
+ }
+}
+
+// -------------------------------------------------------------
+
+LedMeter::LedMeter(QWidget *parent, bool blueState) : ACLevelMeter(parent) {
+ setBackgroundColor(black);
+ QBoxLayout * l = new QVBoxLayout( this );
+ l->setAutoAdd(TRUE);
+ for(int i=0;i<12;i++) {
+ QColor c;
+ if(blueState)
+ c = blue;
+ else {
+ c = red;
+ if(i>=2) c = yellow;
+ if(i>=5) c = green;
+ }
+
+ // put each led in its own frame, since it seems to be broken
+ QFrame *lframe = new QFrame(this);
+ QBoxLayout *lfl = new QVBoxLayout( lframe );
+ lfl->setAutoAdd(TRUE);
+ leds[i] =
+ new KLed(c,KLed::Off, KLed::Sunken, KLed::Circular,lframe);
+ }
+}
+
+void LedMeter::setValue(float f)
+{
+ //printf("value %f\n",f);
+ for(int i=11;i>=0;i--)
+ {
+ if(f > 0.06) leds[i]->setState(KLed::On);
+ else leds[i]->setState(KLed::Off);
+ f /= 1.25;
+ }
+}
+
+// -------------------------------------------------------------
+
+StereoLedMeters::StereoLedMeters(QWidget *parent)
+ : StereoLevelMeter(parent), left(this), right(this)
+{
+ QBoxLayout *layout= new QHBoxLayout(this);
+ layout->addWidget(&left);
+ layout->addWidget(&right);
+}
+
+void StereoLedMeters::setValues(float leftVal, float rightVal) {
+ left.setValue(leftVal);
+ right.setValue(rightVal);
+}
+
+#include "levelmeters.moc"
diff --git a/arts/tools/levelmeters.h b/arts/tools/levelmeters.h
new file mode 100644
index 00000000..42ef0fae
--- /dev/null
+++ b/arts/tools/levelmeters.h
@@ -0,0 +1,168 @@
+ /*
+
+ Copyright (C) 2000 Hans Meine
+ <hans_meine@gmx.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ */
+
+#ifndef ARTS_TOOLS_LEVELMETERS_H
+#define ARTS_TOOLS_LEVELMETERS_H
+
+#include <qobject.h>
+#include <qframe.h>
+#include <qdatetime.h>
+#include <qptrlist.h>
+#include <math.h>
+
+// helper functions
+const float LEVEL_MIN= 1.f/(1<<20); // minimal positive sample for 20 bit resolution
+inline float levelToDB(float level) {
+ if (level<LEVEL_MIN) level=LEVEL_MIN; // prevent from div by 0
+ return (6.f/log(2.f))*log(level);
+}
+
+inline float DBToLevel(float db) {
+ return exp(db/(log(2.f)/6.f));
+}
+
+/**
+ * Base class for a single volume / value bar.
+ */
+class ACLevelMeter : public QFrame {
+ Q_OBJECT
+public:
+ ACLevelMeter(QWidget *parent): QFrame(parent) {}
+public slots:
+ virtual void setValue(float f) = 0;
+};
+
+/**
+ * Base class for a pair of volume / value bars.
+ */
+class StereoLevelMeter : public QFrame {
+ Q_OBJECT
+public:
+ StereoLevelMeter(QWidget *parent): QFrame(parent) {}
+public slots:
+ virtual void setValues(float left, float right) = 0;
+};
+
+/**
+ * Special LevelMeter which remembers min and max of the last [peakMillis]
+ * milliseconds and displays a full bar with optional max/min markers.
+ */
+class PeakBar : public ACLevelMeter {
+ Q_OBJECT
+ bool clipped;
+
+protected:
+ static const int peakMillis; // how long do the peaks stay at their max?
+
+ class Observation {
+ public:
+ QTime time;
+ float value;
+ Observation(float aValue): value(aValue) { time.start(); }
+ };
+ QPtrList<Observation> lastValues;
+
+ float currentValue, maxValue, minValue;
+ void checkMinMax();
+
+ bool displayMinPeak;
+ bool horizontalMode;
+
+ void frameChanged();
+
+public:
+ PeakBar(QWidget *parent);
+
+ QSize sizeHint() const;
+
+ void drawContents(QPainter *p);
+ virtual void setValue(float f);
+};
+
+/**
+ * Special class which draws the Db scale with ticks, numbers and so on.
+ */
+class ScaleView : public QFrame {
+ Q_OBJECT
+protected:
+ QFont font;
+ int dbRange;
+ int upperMargin, lowerMargin;
+public:
+ ScaleView(QWidget *parent);
+ void setDbRange(int db);
+ void setScaleMargins(int margins) { upperMargin= margins; lowerMargin=margins; }
+ QSize sizeHint() const;
+ void drawContents(QPainter *p);
+};
+
+/**
+ * Reusable class which displays two volume bars (left/right) with a Db scale
+ * and clip indicators. Supports / will have a context menu with some display
+ * options like Db range, whether minimal values are also shown and others.
+ */
+class PeakLevelMeters : public StereoLevelMeter {
+ Q_OBJECT
+protected:
+ int dbRange;
+ PeakBar left, right;
+ ScaleView scaleView;
+
+public:
+ PeakLevelMeters(QWidget *parent);
+
+public slots:
+ void setValues(float leftVal, float rightVal);
+ void setDbRange(int db);
+};
+
+class KLed;
+
+/**
+ * Simple LevelMeter implementation with 12 KLeds.
+ * Shows them in green/yellow/red combi if not blueState set, in which
+ * case it's all blue. (Original artscontrol widget by stw.)
+ */
+class LedMeter : public ACLevelMeter {
+ Q_OBJECT
+protected:
+ KLed *leds[12];
+
+public:
+ LedMeter(QWidget *parent, bool blueState = false);
+ void setValue(float f);
+};
+
+/**
+ * A simple pair of LedMeters.
+ */
+class StereoLedMeters : public StereoLevelMeter {
+ Q_OBJECT
+protected:
+ LedMeter left, right;
+
+public:
+ StereoLedMeters(QWidget *parent);
+public slots:
+ void setValues(float left, float right);
+};
+
+#endif /* ARTS_TOOLS_LEVELMETERS_H */
diff --git a/arts/tools/main.cpp b/arts/tools/main.cpp
new file mode 100644
index 00000000..5961dfcd
--- /dev/null
+++ b/arts/tools/main.cpp
@@ -0,0 +1,211 @@
+/*
+
+ Copyright (C) 2000-2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Arnold Krille <arnold@arnoldarts.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 "main.h"
+#include "environmentview.h"
+#include "main.moc"
+#include "levelmeters.h"
+#include "midimanagerview.h"
+#include "audiomanager.h"
+#include "fftscopeview.h"
+#include "mediatypesview.h"
+#include "statusview.h"
+
+#include <objectmanager.h>
+#include <debug.h>
+#include <artsversion.h>
+#include <kartsfloatwatch.h>
+
+#include <qlabel.h>
+#include <qslider.h>
+#include <qpushbutton.h>
+#include <kaction.h>
+#include <kled.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kartsserver.h>
+
+#include <kstdaction.h>
+
+#include "kartswidget.h"
+
+using namespace std;
+using namespace Arts;
+
+void FreeVerbView::closeEvent(QCloseEvent *e) {
+ e->accept();
+ emit closed();
+}
+
+FreeVerbView::FreeVerbView(SimpleSoundServer server) : server(server) {
+ freeverb = DynamicCast(server.createObject("Arts::Synth_FREEVERB"));
+ arts_assert(!freeverb.isNull());
+ freeverb.start();
+
+ // put it into the effect chain
+ effectID = server.outstack().insertTop(freeverb,"FreeVerb");
+
+ GenericGuiFactory factory;
+ Widget gui = factory.createGui(freeverb);
+
+ QBoxLayout * l = new QHBoxLayout( this );
+ if(!gui.isNull())
+ l->add(new KArtsWidget(gui, this));
+ else
+ l->add(new QLabel(i18n("No GUI found for this effect."), this));
+ l->freeze();
+ show();
+}
+
+FreeVerbView::~FreeVerbView() {
+ // remove effect
+ server.outstack().remove(effectID);
+}
+
+
+VControl::VControl( KArtsServer* artsserver, QWidget *parent) : QFrame(parent)
+ , freeVerbView(0)
+ , server( artsserver )
+{
+
+ connect( server, SIGNAL( restartedServer() ), this, SLOT( initaRtsConnections() ) );
+/* if(server.isNull())
+ {
+ KMessageBox::error( 0, i18n("Connection to the soundserver failed - make sure that artsd is really running and that your kdelibs version is not older than kdemultimedia."));
+ exit(1);
+ }*/
+ boxLayout = new QHBoxLayout( this );
+
+ // 0 => 4.0
+ // 200 => 2.0
+ // 400 => 1.0
+ // 600 => 0.5
+ // 800 => 0.25
+ // 1000 => 0.125
+ // 1200 => 0.0 (forced)
+
+ svcguiw = new KArtsWidget( this );
+ boxLayout->addWidget( svcguiw );
+
+ boxLayout->activate();
+ show();
+
+ initaRtsConnections();
+}
+VControl::~VControl() {
+ if ( freeVerbView ) showFreeVerbView();
+}
+
+void VControl::useOldVolumeBar(int old) {
+/* delete stereoMeter;
+ if (old) {
+ stereoMeter= new StereoLedMeters(this);
+ } else {
+ stereoMeter= new PeakLevelMeters(this);
+ }
+ boxLayout->insertWidget(0, stereoMeter);
+ stereoMeter->show();*/
+ if ( old ) {
+ svcgui.left().substyle( 3 );
+ svcgui.right().substyle( 3 );
+ } else {
+ svcgui.left().substyle( 2 );
+ svcgui.right().substyle( 2 );
+ }
+}
+
+void VControl::showFreeVerbView() {
+ if(!freeVerbView) {
+ freeVerbView = new FreeVerbView(server->server());
+ connect(freeVerbView,SIGNAL(closed()),this,SLOT(showFreeVerbView()));
+ } else {
+ delete freeVerbView;
+ freeVerbView = 0;
+ }
+}
+
+void VControl::initaRtsConnections() {
+kdDebug() << k_funcinfo << endl;
+ svcgui = Arts::StereoVolumeControlGui::null();
+ svcgui = Arts::StereoVolumeControlGui( server->server().outVolume() );
+ svcgui.title( i18n( "aRts Master Volume" ).utf8().data() );
+ svcguiw->setContent( Arts::Widget() );
+ svcguiw->setContent( svcgui );
+ useOldVolumeBar( false );
+kdDebug() << k_funcinfo << "done." << endl;
+}
+
+void MainWindow::toggleVolumeBar() {
+ vc->useOldVolumeBar(showOldVolumeDisplay->isChecked());
+}
+
+MainWindow::MainWindow() : KMainWindow(0), kartsserver( new KArtsServer( this ) ) {
+kdDebug() << k_funcinfo << endl;
+ connect( kartsserver, SIGNAL( restartedServer() ), this, SLOT( serverRestarted() ) );
+
+ vc = new VControl( kartsserver, this );
+ setCentralWidget( vc );
+ artsactions = new ArtsActions( kartsserver, actionCollection(), this );
+
+ ( void ) artsactions->actionScopeView();
+ ( void ) artsactions->actionAudioManager();
+ ( void ) artsactions->actionArtsStatusView();
+ ( void ) artsactions->actionMidiManagerView();
+ ( void ) artsactions->actionEnvironmentView();
+ ( void ) artsactions->actionMediaTypesView();
+ ( void ) new KAction( i18n("Toggle Free&Verb"), 0, vc, SLOT( showFreeVerbView() ), actionCollection(), "view_freeverb" );
+ showOldVolumeDisplay=
+ new KToggleAction( i18n( "Old aRts-Control-Style for VU-Meter" /*"&LED-Style Volume Display"*/ ), 0, this,
+ SLOT( toggleVolumeBar() ), actionCollection(), "old_volume_display" );
+ ( void ) KStdAction::quit( this, SLOT( close() ), actionCollection(), "quit_artscontrol" );
+
+ createGUI("artscontrol.rc");
+ resize(20,300);
+ show();
+}
+
+void MainWindow::serverRestarted() {
+kdDebug() << k_funcinfo << endl;
+ KMessageBox::sorry( this, "aRts had to restart!" );
+}
+
+int main(int argc, char **argv) {
+ KAboutData aboutData( "artscontrol", I18N_NOOP("aRts control"),
+ ARTS_VERSION, I18N_NOOP("Control tool for the aRts server"),
+ KAboutData::License_GPL, I18N_NOOP("(c) 2000 Stefan Westerfeld\n(c) 2003 Arnold Krille") );
+ aboutData.addAuthor( "Stefan Westerfeld", I18N_NOOP( "Author and aRts maintainer" ), "stefan@space.twc.de" );
+ aboutData.addAuthor( "Arnold Krille", I18N_NOOP( "Some improvements" ), "arnold@arnoldarts.de" );
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+
+ KApplication app(argc, argv);
+
+ // setup mcop communication
+ QIOManager qiomanager;
+ Dispatcher dispatcher(&qiomanager);
+
+ ObjectManager::the()->provideCapability("kdegui");
+
+ app.setMainWidget(new MainWindow);
+ app.setName("artsbuilder");
+ return app.exec();
+}
diff --git a/arts/tools/main.h b/arts/tools/main.h
new file mode 100644
index 00000000..818e3e89
--- /dev/null
+++ b/arts/tools/main.h
@@ -0,0 +1,110 @@
+/*
+
+ Copyright (C) 2000-2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Arnold Krille <arnold@arnoldarts.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.
+
+ */
+
+#ifndef MAIN_H
+#define MAIN_H
+#include <qiomanager.h>
+#include <dispatcher.h>
+#include <qmessagebox.h>
+#include <kapplication.h>
+#include <qframe.h>
+#include <kmainwindow.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kstdaction.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <artsflow.h>
+#include <soundserver.h>
+#include <qobject.h>
+#include <kartswidget.h>
+#include <flowsystem.h>
+#include <artsmodules.h>
+#include <kartsserver.h>
+
+class LevelMeter;
+class PeakBar;
+class PeakLevelMeter;
+class VScale;
+
+class FreeVerbView : public QWidget {
+ Q_OBJECT
+protected:
+ Arts::Synth_FREEVERB freeverb;
+ Arts::SimpleSoundServer server;
+ long effectID;
+
+ void closeEvent(QCloseEvent *e);
+public:
+ FreeVerbView(Arts::SimpleSoundServer server);
+ ~FreeVerbView();
+signals:
+ void closed();
+};
+
+class KArtsWidget;
+
+class VControl : public QFrame {
+ Q_OBJECT
+protected:
+ class StereoLevelMeter *stereoMeter;
+ FreeVerbView *freeVerbView;
+ Arts::StereoVolumeControl svc;
+ Arts::StereoVolumeControlGui svcgui;
+ KArtsWidget *svcguiw;
+ KArtsServer *server;
+
+ QBoxLayout *boxLayout;
+
+public:
+ VControl( KArtsServer*, QWidget *parent);
+ ~VControl();
+
+public slots:
+ void useOldVolumeBar(int old);
+ void showFreeVerbView();
+private slots:
+ void initaRtsConnections();
+};
+
+#include "artsactions.h"
+
+class MainWindow : public KMainWindow {
+ Q_OBJECT
+protected:
+ VControl *vc;
+ KToggleAction *showOldVolumeDisplay;
+ ArtsActions* artsactions;
+ KArtsServer *kartsserver;
+
+public slots:
+ void toggleVolumeBar();
+
+ void serverRestarted();
+public:
+ MainWindow();
+};
+
+//Arts::Environment::Container defaultEnvironment();
+
+#endif /* MAIN_H */
diff --git a/arts/tools/mediatypesview.cpp b/arts/tools/mediatypesview.cpp
new file mode 100644
index 00000000..b54d2dd1
--- /dev/null
+++ b/arts/tools/mediatypesview.cpp
@@ -0,0 +1,76 @@
+/*
+
+ Copyright (C) 2000-2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Arnold Krille
+ <arnold@arnoldarts.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 <qlayout.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kartsserver.h>
+#include <map>
+#include <kiconloader.h>
+
+#include "mediatypesview.h"
+
+using namespace std;
+using namespace Arts;
+
+MediaTypesView::MediaTypesView( QWidget* parent, const char* name ) : Template_ArtsView( parent,name )
+{
+ this->setCaption( i18n( "Available Media Types" ) );
+ this->setIcon( MainBarIcon( "artsmediatypes", 32 ) );
+ QBoxLayout *l= new QHBoxLayout(this);
+ l->setAutoAdd(true);
+
+ KListView *listView = new KListView(this);
+ listView->addColumn(i18n("Media Type"));
+
+ Arts::TraderQuery q;
+ std::vector<Arts::TraderOffer> *results = q.query();
+ std::map<std::string, bool> done;
+ QString str;
+
+ for(std::vector<Arts::TraderOffer>::iterator i = results->begin(); i != results->end(); i++)
+ {
+ std::vector<string> *ext = (*i).getProperty("Extension");
+
+ for(vector<string>::iterator it = ext->begin(); it != ext->end(); it++)
+ {
+ if(!(*it).length() || done[*it])
+ continue;
+
+ done[*it] = true;
+ (void) new QListViewItem(listView, (*it).c_str());
+ }
+ delete ext;
+ }
+ delete results;
+
+ l->activate();
+ show();
+ setBaseSize(300,200);
+}
+
+MediaTypesView::~MediaTypesView()
+{
+}
+
+#include "mediatypesview.moc"
diff --git a/arts/tools/mediatypesview.h b/arts/tools/mediatypesview.h
new file mode 100644
index 00000000..a55e44a3
--- /dev/null
+++ b/arts/tools/mediatypesview.h
@@ -0,0 +1,36 @@
+/*
+
+ Copyright (C) 2000-2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Arnold Krille
+ <arnold@arnoldarts.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.
+
+ */
+
+#ifndef MEDIATYPESVIEW_H
+#define MEDIATYPESVIEW_H
+
+#include "templateview.h"
+
+class MediaTypesView : public Template_ArtsView {
+ Q_OBJECT
+public:
+ MediaTypesView( QWidget* =0, const char* =0 );
+ ~MediaTypesView();
+};
+
+#endif
diff --git a/arts/tools/midiinstdlg.cpp b/arts/tools/midiinstdlg.cpp
new file mode 100644
index 00000000..ef98f299
--- /dev/null
+++ b/arts/tools/midiinstdlg.cpp
@@ -0,0 +1,179 @@
+/*
+
+ Copyright (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 "midiinstdlg.h"
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include <kapplication.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <kbuttonbox.h>
+#include <kseparator.h>
+#include <kdebug.h>
+#include <qbutton.h>
+#include <qpushbutton.h>
+#include <kstdguiitem.h>
+
+static QStringList getArtsPath()
+{
+ QStringList artsPath;
+ QString dir = locate("data", "artsbuilder/examples/");
+ artsPath += dir;
+ QString home = QDir::homeDirPath() + "/arts/structures/";
+ artsPath += home;
+ return artsPath;
+}
+
+static QStringList listFiles(QString directory, QString extension)
+{
+ QStringList result;
+ QStringList artsPath = getArtsPath();
+
+ QStringList::Iterator it;
+ for ( it = artsPath.begin(); it != artsPath.end(); it++ ) {
+ QString pathname = *it + "/" + directory;
+ QDir dir(pathname, extension);
+ if (dir.exists()) {
+ //kdDebug() << "found dir " << dir.absPath() << endl;
+ result += dir.entryList();
+ }
+ }
+
+ return result;
+}
+
+MidiInstDlg::MidiInstDlg(QWidget *parent)
+ :QDialog(parent,"instrument",TRUE)
+{
+ QVBoxLayout *mainlayout = new QVBoxLayout(this);
+
+// caption label: title
+
+ mainlayout->addSpacing(5);
+ QLabel *captionlabel = new QLabel(this);
+ QFont labelfont(captionlabel->font());
+ labelfont.setPointSize(labelfont.pointSize()*3/2);
+ captionlabel->setFont(labelfont);
+ captionlabel->setText(QString(" ")+i18n("Instrument")+QString(" "));
+ captionlabel->setAlignment(AlignCenter);
+ //min_size(captionlabel);
+ mainlayout->addWidget(captionlabel);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler2 = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler2);
+ mainlayout->addSpacing(5);
+
+// combobox
+
+ box = new QComboBox(this);
+
+ QStringList instruments = listFiles(".","*.arts");
+ QStringList::Iterator it;
+ for ( it = instruments.begin(); it != instruments.end(); it++ ) {
+ QString modname = *it;
+ QString prefix = QString::fromLatin1("instrument_");
+ if (modname.length() > 5)
+ modname.truncate(modname.length()-5); // kill .arts extension
+ if ( (modname.startsWith(prefix)) && (!modname.contains("_GUI")) )
+ box->insertItem(modname.mid(prefix.length()));
+ //kdDebug() << "inserted instrument: " << modname.mid(prefix.length()) << endl;
+ }
+
+
+ QStringList maps = listFiles(".","*.arts-map");
+
+ for ( it = maps.begin(); it != maps.end(); it++ ) {
+ QString modname = *it;
+ QString prefix = QString::fromLatin1("instrument_");
+ if (modname.length() > 9)
+ modname.truncate(modname.length()-9); // kill .arts-map extension
+ if (modname.startsWith(prefix))
+ box->insertItem(modname.mid(prefix.length()));
+ //kdDebug() << "inserted map: " << modname.mid(prefix.length()) << endl;
+ }
+
+ mainlayout->addWidget(box);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler);
+ mainlayout->addSpacing(5);
+
+// buttons
+
+ QHBoxLayout *buttonlayout = new QHBoxLayout;
+ mainlayout->addSpacing(5);
+ mainlayout->addLayout(buttonlayout);
+ mainlayout->addSpacing(5);
+
+ buttonlayout->addSpacing(5);
+ KButtonBox *bbox = new KButtonBox(this);
+
+ bbox->addButton(KStdGuiItem::help(), this, SLOT( help() ));
+ bbox->addStretch(1);
+
+ QButton *okbutton = bbox->addButton(KStdGuiItem::ok());
+ connect( okbutton, SIGNAL( clicked() ), SLOT(accept() ) );
+
+ bbox->layout();
+
+ buttonlayout->addWidget(bbox);
+ buttonlayout->addSpacing(5);
+
+ mainlayout->freeze();
+}
+
+QCString MidiInstDlg::filename()
+{
+ QStringList artsPath = getArtsPath();
+ QString instrument = box->currentText();
+
+ QStringList::Iterator it;
+
+ for ( it = artsPath.begin(); it != artsPath.end(); it++ ) {
+ QString pathname = *it + QString::fromLatin1("/instrument_") + instrument + QString::fromLatin1(".arts");
+ QFileInfo fi(pathname);
+ if (fi.exists() && fi.isReadable())
+ return QFile::encodeName(pathname);
+
+ pathname = *it + QString::fromLatin1("/instrument_") + instrument + QString::fromLatin1(".arts-map");
+ fi.setFile(pathname);
+ if (fi.exists() && fi.isReadable())
+ return QFile::encodeName(pathname);
+ }
+
+ return "";
+}
+
+void MidiInstDlg::help()
+{
+ KApplication::kApplication()->invokeHelp("", "artsbuilder");
+}
+
+#include "midiinstdlg.moc"
diff --git a/arts/tools/midiinstdlg.h b/arts/tools/midiinstdlg.h
new file mode 100644
index 00000000..95d7b677
--- /dev/null
+++ b/arts/tools/midiinstdlg.h
@@ -0,0 +1,38 @@
+/*
+
+ Copyright (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.
+
+ */
+
+#ifndef ARTS_TOOLS_MIDIINSTDLG_H
+#define ARTS_TOOLS_MIDIINSTDLG_H
+
+#include <qdialog.h>
+#include <qcombobox.h>
+#include <qcstring.h>
+
+class MidiInstDlg :public QDialog {
+ Q_OBJECT
+ QComboBox *box;
+public:
+ MidiInstDlg(QWidget *parent);
+ QCString filename();
+public slots:
+ void help();
+};
+#endif
diff --git a/arts/tools/midimanagerdlg.ui b/arts/tools/midimanagerdlg.ui
new file mode 100644
index 00000000..78941e4c
--- /dev/null
+++ b/arts/tools/midimanagerdlg.ui
@@ -0,0 +1,151 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>MidiManagerDlg</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>MidiManagerDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>462</width>
+ <height>266</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>MIDI Manager</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>MIDI inputs:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>MIDI outputs:</string>
+ </property>
+ </widget>
+ <widget class="QListBox" row="1" column="0">
+ <property name="name">
+ <cstring>inputsListBox</cstring>
+ </property>
+ </widget>
+ <widget class="QListBox" row="1" column="2">
+ <property name="name">
+ <cstring>outputsListBox</cstring>
+ </property>
+ </widget>
+ <widget class="QFrame" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Frame5</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton" row="0" column="0">
+ <property name="name">
+ <cstring>AddButton_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Add...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="1">
+ <property name="name">
+ <cstring>RemoveButton_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>connectButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Connect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="3">
+ <property name="name">
+ <cstring>disconnectButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Disconnect</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QFrame" row="1" column="1">
+ <property name="name">
+ <cstring>connectionFrame</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/arts/tools/midimanagerview.cpp b/arts/tools/midimanagerview.cpp
new file mode 100644
index 00000000..764f4ee5
--- /dev/null
+++ b/arts/tools/midimanagerview.cpp
@@ -0,0 +1,260 @@
+/*
+
+ Copyright (C) 2000 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.
+
+ Permission is also granted to link this program with the Qt
+ library, treating Qt like a library that normally accompanies the
+ operating system kernel, whether or not that is in fact the case.
+
+ */
+
+#include "midimanagerview.h"
+#define protected public
+#include "midimanagerwidget.h"
+#undef protected
+#include <qpushbutton.h>
+#include <qlistbox.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <stdio.h>
+#include <kaction.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <soundserver.h>
+#include "artsmidi.h"
+#include "artsmodules.h"
+#include "midiportdlg.h"
+#include "midiinstdlg.h"
+
+#include <kstdaction.h>
+
+using namespace Arts;
+using namespace std;
+
+/* quick hack as long as the sound server doesn't support environments */
+Arts::Environment::Container defaultEnvironment()
+{
+ Arts::SimpleSoundServer server = Reference("global:Arts_SimpleSoundServer");
+ Arts::Environment::Container d =
+ Arts::DynamicCast(server._getChild("defaultEnvironment"));
+
+ if(d.isNull())
+ {
+ d = Arts::DynamicCast(
+ server.createObject("Arts::Environment::Container"));
+ server._addChild(d,"defaultEnvironment");
+ }
+ return d;
+}
+
+class MidiManagerItem : public QListBoxText {
+public:
+ MidiClientInfo info;
+
+ MidiManagerItem(const MidiClientInfo &info) :info(info)
+ {
+ }
+ QString text () const {
+ return QString::fromUtf8(info.title.c_str());
+ }
+
+};
+
+class ConnectionWidget : public QWidget {
+public:
+ MidiManagerView *v;
+ ConnectionWidget(MidiManagerView *v, QWidget *parent) : QWidget(parent), v(v)
+ {
+ }
+ void paintEvent(QPaintEvent * /*event*/)
+ {
+ QPainter painter;
+ painter.begin(this);
+// painter.fillRect(event->rect(),white);
+
+ unsigned int in;
+ for(in = 0; in < v->widget->inputsListBox->count(); in++)
+ {
+ vector<long>::iterator conn;
+ MidiManagerItem *item = (MidiManagerItem *)v->widget->inputsListBox->item(in);
+ for(conn = item->info.connections.begin();
+ conn != item->info.connections.end(); conn++)
+ {
+ MidiManagerItem *outitem = v->itemMap[*conn];
+ QRect r1 = v->widget->inputsListBox->itemRect(item);
+ QRect r2 = v->widget->outputsListBox->itemRect(outitem);
+
+ if(r1.height() > 0 && r2.height() > 0)
+ {
+ painter.drawLine(0,(r1.top()+r1.bottom()) / 2,
+ width(), (r2.top()+r2.bottom())/2);
+ }
+ }
+ }
+ painter.end();
+ }
+};
+
+MidiManagerView::MidiManagerView()
+ : manager(Reference("global:Arts_MidiManager"))
+{
+ QTimer *updatetimer = new QTimer(this);
+ updatetimer->start(5000);
+ connect(updatetimer,SIGNAL(timeout()),this,SLOT(updateLists()));
+
+ widget = new MidiManagerWidget(this);
+ setCentralWidget(widget);
+ setCaption(i18n("MIDI Manager"));
+ setIcon( MainBarIcon( "artsfftscope", 32 ) );
+
+ (void)new KAction(i18n("&System MIDI Port (OSS)"), 0, this, SLOT(addOSSMidiPort()),
+ actionCollection(), "add_oss_midi_port");
+ (void)new KAction(i18n("&aRts Synthesis MIDI Output"), 0, this,
+ SLOT(addArtsMidiOutput()), actionCollection(), "add_arts_midi_output");
+
+ (void) KStdAction::quit( this, SLOT(close()), actionCollection());
+ connect(widget->connectButton,SIGNAL(clicked()), this, SLOT(slotConnect()));
+ connect(widget->disconnectButton,SIGNAL(clicked()), this, SLOT(slotDisconnect()));
+
+ connectionWidget = new ConnectionWidget(this, widget->connectionFrame);
+ connectionWidget->setMinimumSize(60,10);
+ widget->connectionFrameLayout->addWidget( connectionWidget, 0, 0 );
+
+ updateLists();
+ createGUI( "artsmidimanagerview.rc");
+ show();
+ setCaption(i18n("MIDI Manager"));
+ setIcon( MainBarIcon( "artsfftscope", 32 ) );
+}
+
+void MidiManagerView::closeEvent(QCloseEvent *e)
+{
+ e->accept();
+ emit closed();
+}
+
+void MidiManagerView::updateLists()
+{
+ vector<MidiClientInfo> *clients = manager.clients();
+ vector<MidiClientInfo>::iterator i;
+
+// keep selection over updating
+ MidiManagerItem *src =
+ (MidiManagerItem *)widget->inputsListBox->item(widget->inputsListBox->currentItem());
+ MidiManagerItem *dest =
+ (MidiManagerItem *)widget->outputsListBox->item(widget->outputsListBox->currentItem());
+
+ long srcID = src?src->info.ID:0;
+ long destID = dest?dest->info.ID:0;
+
+// clear everything, and rebuild
+ itemMap.clear();
+ widget->inputsListBox->clear();
+ widget->outputsListBox->clear();
+ for(i = clients->begin(); i != clients->end(); i++)
+ {
+ QListBox *box;
+ if(i->direction == mcdPlay)
+ box = widget->inputsListBox;
+ else
+ box = widget->outputsListBox;
+
+ MidiManagerItem *item = new MidiManagerItem(*i);
+ itemMap[item->info.ID] = item;
+ box->insertItem(item);
+ }
+ delete clients;
+
+// restore selection
+ if(srcID && itemMap[srcID])
+ widget->inputsListBox->setSelected(itemMap[srcID],true);
+ if(destID && itemMap[destID])
+ widget->outputsListBox->setSelected(itemMap[destID],true);
+ connectionWidget->repaint();
+}
+
+void MidiManagerView::slotConnect()
+{
+ MidiManagerItem *src =
+ (MidiManagerItem *)widget->inputsListBox->item(widget->inputsListBox->currentItem());
+ MidiManagerItem *dest =
+ (MidiManagerItem *)widget->outputsListBox->item(widget->outputsListBox->currentItem());
+ if(src && dest)
+ {
+ manager.connect(src->info.ID,dest->info.ID);
+ updateLists();
+ }
+}
+
+void MidiManagerView::slotDisconnect()
+{
+ MidiManagerItem *src =
+ (MidiManagerItem *)widget->inputsListBox->item(widget->inputsListBox->currentItem());
+ MidiManagerItem *dest =
+ (MidiManagerItem *)widget->outputsListBox->item(widget->outputsListBox->currentItem());
+ if(src && dest)
+ {
+ manager.disconnect(src->info.ID,dest->info.ID);
+ updateLists();
+ }
+}
+
+void MidiManagerView::addOSSMidiPort()
+{
+ //lukas: no i18n here, QDialog's CTOR doesn't know about QString
+ //lukas: can't use that with const char *, i18n()'ed in the dialog itself
+ MidiPortDlg *dlg = new MidiPortDlg(0,"/dev/midi","OSS Midi Port");
+
+ if(dlg->exec())
+ {
+ SoundServer s = Reference("global:Arts_SoundServer");
+ if(!s.isNull())
+ {
+ RawMidiPort p = DynamicCast(s.createObject("Arts::RawMidiPort"));
+ p.device(dlg->device());
+ if(p.open())
+ p._addChild(p,"avoid_delete");
+ }
+ }
+ delete dlg;
+}
+
+void MidiManagerView::addArtsMidiOutput()
+{
+ MidiInstDlg *dlg = new MidiInstDlg(0);
+
+ if(dlg->exec())
+ {
+ SoundServer s = Reference("global:Arts_SoundServer");
+ if(!s.isNull())
+ {
+ /*
+ Synth_MIDI_TEST t
+ = DynamicCast(s.createObject("Arts::Synth_MIDI_TEST"));
+ t.filename(dlg->filename().data());
+ t.start();
+ t._addChild(t,"avoid_delete");
+ */
+ Environment::InstrumentItem item = DynamicCast(
+ defaultEnvironment().createItem("Arts::Environment::InstrumentItem"));
+ if(!item.isNull())
+ item.filename(dlg->filename().data());
+ }
+ }
+}
+#include "midimanagerview.moc"
diff --git a/arts/tools/midimanagerview.h b/arts/tools/midimanagerview.h
new file mode 100644
index 00000000..7ab9d7ff
--- /dev/null
+++ b/arts/tools/midimanagerview.h
@@ -0,0 +1,61 @@
+/*
+
+ Copyright (C) 2000 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.
+
+ Permission is also granted to link this program with the Qt
+ library, treating Qt like a library that normally accompanies the
+ operating system kernel, whether or not that is in fact the case.
+
+ */
+
+#ifndef ARTS_TOOLS_MIDIMANAGERVIEW_H
+#define ARTS_TOOLS_MIDIMANAGERVIEW_H
+
+#include <kmainwindow.h>
+#include "artsmidi.h"
+#include <map>
+
+class ConnectionWidget;
+class MidiManagerItem;
+class MidiManagerWidget;
+
+class MidiManagerView : public KMainWindow {
+ Q_OBJECT
+protected:
+ friend class ConnectionWidget;
+ Arts::MidiManager manager;
+ MidiManagerWidget *widget;
+ ConnectionWidget *connectionWidget;
+ std::map<long, MidiManagerItem *> itemMap;
+
+public:
+ MidiManagerView();
+
+ void closeEvent(QCloseEvent *e);
+public slots:
+ void updateLists();
+ void slotConnect();
+ void slotDisconnect();
+ void addOSSMidiPort();
+ void addArtsMidiOutput();
+
+signals:
+ void closed();
+};
+
+#endif
diff --git a/arts/tools/midimanagerwidget.ui b/arts/tools/midimanagerwidget.ui
new file mode 100644
index 00000000..115626d0
--- /dev/null
+++ b/arts/tools/midimanagerwidget.ui
@@ -0,0 +1,135 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>MidiManagerWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>MidiManagerWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>454</width>
+ <height>266</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>MIDI Manager</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>MIDI inputs:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>MIDI outputs:</string>
+ </property>
+ </widget>
+ <widget class="QListBox" row="1" column="0">
+ <property name="name">
+ <cstring>inputsListBox</cstring>
+ </property>
+ </widget>
+ <widget class="QListBox" row="1" column="2">
+ <property name="name">
+ <cstring>outputsListBox</cstring>
+ </property>
+ </widget>
+ <widget class="QFrame" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Frame5</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>connectButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Connect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="3">
+ <property name="name">
+ <cstring>disconnectButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Disconnect</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QFrame" row="1" column="1">
+ <property name="name">
+ <cstring>connectionFrame</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/arts/tools/midiportdlg.cpp b/arts/tools/midiportdlg.cpp
new file mode 100644
index 00000000..c7e61e03
--- /dev/null
+++ b/arts/tools/midiportdlg.cpp
@@ -0,0 +1,111 @@
+/*
+
+ Copyright (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 "midiportdlg.h"
+#include <klocale.h>
+
+#include <kapplication.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <kseparator.h>
+#include <kbuttonbox.h>
+#include <qlineedit.h>
+#include <qbutton.h>
+#include <qpushbutton.h>
+#include <kstdguiitem.h>
+
+MidiPortDlg::MidiPortDlg(QWidget *parent, const char *oldname, const char *title) :QDialog(parent,title,TRUE)
+{
+ QVBoxLayout *mainlayout = new QVBoxLayout(this);
+
+// caption label: title
+
+ mainlayout->addSpacing(5);
+ QLabel *captionlabel = new QLabel(this);
+ QFont labelfont(captionlabel->font());
+ labelfont.setPointSize(labelfont.pointSize()*3/2);
+ captionlabel->setFont(labelfont);
+ captionlabel->setText(i18n("OSS MIDI Port"));
+ captionlabel->setAlignment(AlignCenter);
+ //min_size(captionlabel);
+ mainlayout->addWidget(captionlabel);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler2 = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler2);
+ mainlayout->addSpacing(5);
+
+// editwidget
+
+ edit = new QLineEdit(this);
+ edit->setText(oldname);
+ //min_size(edit);
+
+ mainlayout->addWidget(edit);
+
+// hruler
+
+ mainlayout->addSpacing(5);
+ KSeparator *ruler = new KSeparator( KSeparator::HLine, this);
+ mainlayout->addWidget(ruler);
+ mainlayout->addSpacing(5);
+
+// buttons
+
+ QHBoxLayout *buttonlayout = new QHBoxLayout;
+ mainlayout->addSpacing(5);
+ mainlayout->addLayout(buttonlayout);
+ mainlayout->addSpacing(5);
+
+ buttonlayout->addSpacing(5);
+ KButtonBox *bbox = new KButtonBox(this);
+
+ QPushButton *helpbutton = bbox->addButton(KStdGuiItem::help(), this, SLOT( help() ));
+ bbox->addStretch(1);
+ helpbutton->setAutoDefault( true );
+ helpbutton->setDefault( true );
+
+ QPushButton *okbutton = bbox->addButton(KStdGuiItem::ok());
+ connect( okbutton, SIGNAL( clicked() ), SLOT(accept() ) );
+ okbutton->setAutoDefault( true );
+ okbutton->setDefault( true );
+
+ bbox->layout();
+
+ buttonlayout->addWidget(bbox);
+ buttonlayout->addSpacing(5);
+
+ mainlayout->freeze();
+}
+
+const char *MidiPortDlg::device()
+{
+ return edit->text().ascii();
+}
+
+void MidiPortDlg::help()
+{
+ KApplication::kApplication()->invokeHelp("", "artsbuilder");
+}
+
+#include "midiportdlg.moc"
diff --git a/arts/tools/midiportdlg.h b/arts/tools/midiportdlg.h
new file mode 100644
index 00000000..4664bebc
--- /dev/null
+++ b/arts/tools/midiportdlg.h
@@ -0,0 +1,42 @@
+/*
+
+ Copyright (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.
+
+ */
+
+#ifndef ARTS_TOOLS_MIDIPORTDLG_H
+#define ARTS_TOOLS_MIDIPORTDLG_H
+
+#include <qdialog.h>
+#include <qtimer.h>
+#include <qlabel.h>
+#include <qscrollbar.h>
+#include <qlineedit.h>
+#include <qlayout.h>
+
+class MidiPortDlg :public QDialog {
+ Q_OBJECT
+ QLineEdit *edit;
+public:
+ MidiPortDlg(QWidget *parent, const char *device, const char *title);
+ const char *device();
+
+public slots:
+ void help();
+};
+#endif
diff --git a/arts/tools/pics/Makefile.am b/arts/tools/pics/Makefile.am
new file mode 100644
index 00000000..779ff362
--- /dev/null
+++ b/arts/tools/pics/Makefile.am
@@ -0,0 +1,2 @@
+KDE_ICON = AUTO
+
diff --git a/arts/tools/pics/cr128-action-artsaudiomanager.png b/arts/tools/pics/cr128-action-artsaudiomanager.png
new file mode 100644
index 00000000..d659b4b5
--- /dev/null
+++ b/arts/tools/pics/cr128-action-artsaudiomanager.png
Binary files differ
diff --git a/arts/tools/pics/cr128-action-artsenvironment.png b/arts/tools/pics/cr128-action-artsenvironment.png
new file mode 100644
index 00000000..5075c8cc
--- /dev/null
+++ b/arts/tools/pics/cr128-action-artsenvironment.png
Binary files differ
diff --git a/arts/tools/pics/cr128-action-artsfftscope.png b/arts/tools/pics/cr128-action-artsfftscope.png
new file mode 100644
index 00000000..0e1b512b
--- /dev/null
+++ b/arts/tools/pics/cr128-action-artsfftscope.png
Binary files differ
diff --git a/arts/tools/pics/cr128-action-artsmediatypes.png b/arts/tools/pics/cr128-action-artsmediatypes.png
new file mode 100644
index 00000000..877bf20a
--- /dev/null
+++ b/arts/tools/pics/cr128-action-artsmediatypes.png
Binary files differ
diff --git a/arts/tools/pics/cr128-action-artsmidimanager.png b/arts/tools/pics/cr128-action-artsmidimanager.png
new file mode 100644
index 00000000..ab5b672a
--- /dev/null
+++ b/arts/tools/pics/cr128-action-artsmidimanager.png
Binary files differ
diff --git a/arts/tools/pics/cr16-action-artsaudiomanager.png b/arts/tools/pics/cr16-action-artsaudiomanager.png
new file mode 100644
index 00000000..43e287cd
--- /dev/null
+++ b/arts/tools/pics/cr16-action-artsaudiomanager.png
Binary files differ
diff --git a/arts/tools/pics/cr16-action-artsenvironment.png b/arts/tools/pics/cr16-action-artsenvironment.png
new file mode 100644
index 00000000..62b04e42
--- /dev/null
+++ b/arts/tools/pics/cr16-action-artsenvironment.png
Binary files differ
diff --git a/arts/tools/pics/cr16-action-artsfftscope.png b/arts/tools/pics/cr16-action-artsfftscope.png
new file mode 100644
index 00000000..4ef12da5
--- /dev/null
+++ b/arts/tools/pics/cr16-action-artsfftscope.png
Binary files differ
diff --git a/arts/tools/pics/cr16-action-artsmediatypes.png b/arts/tools/pics/cr16-action-artsmediatypes.png
new file mode 100644
index 00000000..592e300b
--- /dev/null
+++ b/arts/tools/pics/cr16-action-artsmediatypes.png
Binary files differ
diff --git a/arts/tools/pics/cr16-action-artsmidimanager.png b/arts/tools/pics/cr16-action-artsmidimanager.png
new file mode 100644
index 00000000..44948a1e
--- /dev/null
+++ b/arts/tools/pics/cr16-action-artsmidimanager.png
Binary files differ
diff --git a/arts/tools/pics/cr22-action-artsaudiomanager.png b/arts/tools/pics/cr22-action-artsaudiomanager.png
new file mode 100644
index 00000000..9a103e73
--- /dev/null
+++ b/arts/tools/pics/cr22-action-artsaudiomanager.png
Binary files differ
diff --git a/arts/tools/pics/cr22-action-artsenvironment.png b/arts/tools/pics/cr22-action-artsenvironment.png
new file mode 100644
index 00000000..3e4c3a04
--- /dev/null
+++ b/arts/tools/pics/cr22-action-artsenvironment.png
Binary files differ
diff --git a/arts/tools/pics/cr22-action-artsfftscope.png b/arts/tools/pics/cr22-action-artsfftscope.png
new file mode 100644
index 00000000..1104ab76
--- /dev/null
+++ b/arts/tools/pics/cr22-action-artsfftscope.png
Binary files differ
diff --git a/arts/tools/pics/cr22-action-artsmediatypes.png b/arts/tools/pics/cr22-action-artsmediatypes.png
new file mode 100644
index 00000000..271de38e
--- /dev/null
+++ b/arts/tools/pics/cr22-action-artsmediatypes.png
Binary files differ
diff --git a/arts/tools/pics/cr22-action-artsmidimanager.png b/arts/tools/pics/cr22-action-artsmidimanager.png
new file mode 100644
index 00000000..2d21c16a
--- /dev/null
+++ b/arts/tools/pics/cr22-action-artsmidimanager.png
Binary files differ
diff --git a/arts/tools/pics/cr32-action-artsaudiomanager.png b/arts/tools/pics/cr32-action-artsaudiomanager.png
new file mode 100644
index 00000000..1ce95887
--- /dev/null
+++ b/arts/tools/pics/cr32-action-artsaudiomanager.png
Binary files differ
diff --git a/arts/tools/pics/cr32-action-artsenvironment.png b/arts/tools/pics/cr32-action-artsenvironment.png
new file mode 100644
index 00000000..78b9936c
--- /dev/null
+++ b/arts/tools/pics/cr32-action-artsenvironment.png
Binary files differ
diff --git a/arts/tools/pics/cr32-action-artsfftscope.png b/arts/tools/pics/cr32-action-artsfftscope.png
new file mode 100644
index 00000000..a70320f8
--- /dev/null
+++ b/arts/tools/pics/cr32-action-artsfftscope.png
Binary files differ
diff --git a/arts/tools/pics/cr32-action-artsmediatypes.png b/arts/tools/pics/cr32-action-artsmediatypes.png
new file mode 100644
index 00000000..8f44fe1a
--- /dev/null
+++ b/arts/tools/pics/cr32-action-artsmediatypes.png
Binary files differ
diff --git a/arts/tools/pics/cr32-action-artsmidimanager.png b/arts/tools/pics/cr32-action-artsmidimanager.png
new file mode 100644
index 00000000..90d6c565
--- /dev/null
+++ b/arts/tools/pics/cr32-action-artsmidimanager.png
Binary files differ
diff --git a/arts/tools/pics/cr48-action-artsaudiomanager.png b/arts/tools/pics/cr48-action-artsaudiomanager.png
new file mode 100644
index 00000000..048a567e
--- /dev/null
+++ b/arts/tools/pics/cr48-action-artsaudiomanager.png
Binary files differ
diff --git a/arts/tools/pics/cr48-action-artsenvironment.png b/arts/tools/pics/cr48-action-artsenvironment.png
new file mode 100644
index 00000000..f12b27da
--- /dev/null
+++ b/arts/tools/pics/cr48-action-artsenvironment.png
Binary files differ
diff --git a/arts/tools/pics/cr48-action-artsfftscope.png b/arts/tools/pics/cr48-action-artsfftscope.png
new file mode 100644
index 00000000..c5d832af
--- /dev/null
+++ b/arts/tools/pics/cr48-action-artsfftscope.png
Binary files differ
diff --git a/arts/tools/pics/cr48-action-artsmediatypes.png b/arts/tools/pics/cr48-action-artsmediatypes.png
new file mode 100644
index 00000000..7f297365
--- /dev/null
+++ b/arts/tools/pics/cr48-action-artsmediatypes.png
Binary files differ
diff --git a/arts/tools/pics/cr48-action-artsmidimanager.png b/arts/tools/pics/cr48-action-artsmidimanager.png
new file mode 100644
index 00000000..cdec56ba
--- /dev/null
+++ b/arts/tools/pics/cr48-action-artsmidimanager.png
Binary files differ
diff --git a/arts/tools/pics/cr64-action-artsaudiomanager.png b/arts/tools/pics/cr64-action-artsaudiomanager.png
new file mode 100644
index 00000000..088969ac
--- /dev/null
+++ b/arts/tools/pics/cr64-action-artsaudiomanager.png
Binary files differ
diff --git a/arts/tools/pics/cr64-action-artsenvironment.png b/arts/tools/pics/cr64-action-artsenvironment.png
new file mode 100644
index 00000000..13a79a9b
--- /dev/null
+++ b/arts/tools/pics/cr64-action-artsenvironment.png
Binary files differ
diff --git a/arts/tools/pics/cr64-action-artsfftscope.png b/arts/tools/pics/cr64-action-artsfftscope.png
new file mode 100644
index 00000000..53627e6f
--- /dev/null
+++ b/arts/tools/pics/cr64-action-artsfftscope.png
Binary files differ
diff --git a/arts/tools/pics/cr64-action-artsmediatypes.png b/arts/tools/pics/cr64-action-artsmediatypes.png
new file mode 100644
index 00000000..b5969d0f
--- /dev/null
+++ b/arts/tools/pics/cr64-action-artsmediatypes.png
Binary files differ
diff --git a/arts/tools/pics/cr64-action-artsmidimanager.png b/arts/tools/pics/cr64-action-artsmidimanager.png
new file mode 100644
index 00000000..e363de1e
--- /dev/null
+++ b/arts/tools/pics/cr64-action-artsmidimanager.png
Binary files differ
diff --git a/arts/tools/pics/crsc-action-artsaudiomanager.svgz b/arts/tools/pics/crsc-action-artsaudiomanager.svgz
new file mode 100644
index 00000000..fa7c0105
--- /dev/null
+++ b/arts/tools/pics/crsc-action-artsaudiomanager.svgz
Binary files differ
diff --git a/arts/tools/pics/crsc-action-artsenvironment.svgz b/arts/tools/pics/crsc-action-artsenvironment.svgz
new file mode 100644
index 00000000..7fa3fc30
--- /dev/null
+++ b/arts/tools/pics/crsc-action-artsenvironment.svgz
Binary files differ
diff --git a/arts/tools/pics/crsc-action-artsfftscope.svgz b/arts/tools/pics/crsc-action-artsfftscope.svgz
new file mode 100644
index 00000000..e0938861
--- /dev/null
+++ b/arts/tools/pics/crsc-action-artsfftscope.svgz
Binary files differ
diff --git a/arts/tools/pics/crsc-action-artsmediatypes.svgz b/arts/tools/pics/crsc-action-artsmediatypes.svgz
new file mode 100644
index 00000000..46fbdd30
--- /dev/null
+++ b/arts/tools/pics/crsc-action-artsmediatypes.svgz
Binary files differ
diff --git a/arts/tools/pics/crsc-action-artsmidimanager.svgz b/arts/tools/pics/crsc-action-artsmidimanager.svgz
new file mode 100644
index 00000000..9ca209dc
--- /dev/null
+++ b/arts/tools/pics/crsc-action-artsmidimanager.svgz
Binary files differ
diff --git a/arts/tools/pics/hi128-app-artscontrol.png b/arts/tools/pics/hi128-app-artscontrol.png
new file mode 100644
index 00000000..c6586076
--- /dev/null
+++ b/arts/tools/pics/hi128-app-artscontrol.png
Binary files differ
diff --git a/arts/tools/pics/hi16-app-artscontrol.png b/arts/tools/pics/hi16-app-artscontrol.png
new file mode 100644
index 00000000..b39d4682
--- /dev/null
+++ b/arts/tools/pics/hi16-app-artscontrol.png
Binary files differ
diff --git a/arts/tools/pics/hi22-app-artscontrol.png b/arts/tools/pics/hi22-app-artscontrol.png
new file mode 100644
index 00000000..dcb1d88c
--- /dev/null
+++ b/arts/tools/pics/hi22-app-artscontrol.png
Binary files differ
diff --git a/arts/tools/pics/hi32-app-artscontrol.png b/arts/tools/pics/hi32-app-artscontrol.png
new file mode 100644
index 00000000..98525ed1
--- /dev/null
+++ b/arts/tools/pics/hi32-app-artscontrol.png
Binary files differ
diff --git a/arts/tools/pics/hi48-app-artscontrol.png b/arts/tools/pics/hi48-app-artscontrol.png
new file mode 100644
index 00000000..14549fbf
--- /dev/null
+++ b/arts/tools/pics/hi48-app-artscontrol.png
Binary files differ
diff --git a/arts/tools/pics/hi64-app-artscontrol.png b/arts/tools/pics/hi64-app-artscontrol.png
new file mode 100644
index 00000000..f9064f92
--- /dev/null
+++ b/arts/tools/pics/hi64-app-artscontrol.png
Binary files differ
diff --git a/arts/tools/pics/hisc-app-artscontrol.svgz b/arts/tools/pics/hisc-app-artscontrol.svgz
new file mode 100644
index 00000000..7763a33a
--- /dev/null
+++ b/arts/tools/pics/hisc-app-artscontrol.svgz
Binary files differ
diff --git a/arts/tools/statusview.cpp b/arts/tools/statusview.cpp
new file mode 100644
index 00000000..7606b3ef
--- /dev/null
+++ b/arts/tools/statusview.cpp
@@ -0,0 +1,95 @@
+/*
+
+ Copyright (C) 2000-2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Arnold Krille
+ <arnold@arnoldarts.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 <qlayout.h>
+#include <klocale.h>
+#include <qpushbutton.h>
+#include <qwidget.h>
+#include <qtimer.h>
+#include <qlabel.h>
+
+#include "statusview.h"
+
+using namespace std;
+using namespace Arts;
+
+ArtsStatusView::ArtsStatusView(Arts::SoundServer a_server, QWidget* parent, const char* name )
+ : Template_ArtsView( parent,name )
+ , server(a_server)
+{
+ this->setCaption( i18n( "aRts Status" ) );
+ QBoxLayout *l= new QVBoxLayout(this);
+ //l->setAutoAdd(TRUE);
+
+ RealtimeStatus rs= server.realtimeStatus();
+ l->addWidget(new QLabel(rs==rtRealtime?
+ i18n("Artsd is running with realtime scheduling."):
+ rs==rtNoSupport?
+ i18n("Your system does not support realtime scheduling."):
+ rs==rtNoWrapper?
+ i18n("Artsd is not configured for realtime scheduling\n "
+ "or was manually started without artswrapper."):
+ i18n("Artsd should run with realtime scheduling,\n but it "
+ "does not (Is artswrapper suid root?)."),
+ this, "realtimeLabel"));
+ l->addSpacing(10);
+
+ suspendLabel= new QLabel(i18n("Determining suspend status..."),
+ this, "suspendLabel");
+ l->addWidget(suspendLabel);
+ l->addSpacing(6);
+ l->setMargin(6);
+
+ suspendButton= new QPushButton(this, "suspendButton");
+ suspendButton->setText(i18n("&Suspend Now"));
+ l->addWidget(suspendButton);
+ connect(suspendButton, SIGNAL(clicked()), this, SLOT(suspendButtonClicked()));
+
+ artsPollStatusTimer= new QTimer(this);
+ connect(artsPollStatusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
+ artsPollStatusTimer->start(1000);
+ //l->activate();
+ show();
+}
+
+void ArtsStatusView::suspendButtonClicked()
+{
+ (void)server.suspend(); // TODO: error msg if suspend not possible?
+}
+
+void ArtsStatusView::updateStatus()
+{
+ long seconds= server.secondsUntilSuspend();
+ if (seconds<0)
+ suspendLabel->setText(i18n("The aRts sound daemon will not autosuspend right\n"
+ "now since there are active modules."));
+ else if (seconds==0)
+ suspendLabel->setText(i18n("The aRts sound daemon is suspended. Legacy\n "
+ "applications can use the sound card now."));
+ else
+ suspendLabel->setText(i18n("Autosuspend will happen in %1 seconds.").
+ arg(seconds));
+ suspendButton->setEnabled(seconds>0);
+}
+
+#include "statusview.moc"
diff --git a/arts/tools/statusview.h b/arts/tools/statusview.h
new file mode 100644
index 00000000..6ded00af
--- /dev/null
+++ b/arts/tools/statusview.h
@@ -0,0 +1,52 @@
+/*
+
+ Copyright (C) 2000-2001 Stefan Westerfeld
+ <stefan@space.twc.de>
+ 2003 Arnold Krille
+ <arnold@arnoldarts.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.
+
+ */
+
+#ifndef STATUSVIEW_H
+#define STATUSVIEW_H
+
+#include <qwidget.h>
+#include <arts/soundserver.h>
+
+#include "templateview.h"
+
+class QButton;
+class QTimer;
+class QLabel;
+
+class ArtsStatusView : public Template_ArtsView {
+ Q_OBJECT
+public:
+ ArtsStatusView(Arts::SoundServer server, QWidget* =0, const char* =0 );
+
+public slots:
+ void updateStatus();
+ void suspendButtonClicked();
+
+protected:
+ QTimer *artsPollStatusTimer;
+ Arts::SoundServer server;
+ QLabel *suspendLabel;
+ QButton *suspendButton;
+};
+
+#endif
diff --git a/arts/tools/templateview.cpp b/arts/tools/templateview.cpp
new file mode 100644
index 00000000..ecf7a0e8
--- /dev/null
+++ b/arts/tools/templateview.cpp
@@ -0,0 +1,39 @@
+/*
+
+ Copyright (C) 2003 Arnold Krille <arnold@arnoldarts.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 "templateview.h"
+
+//#include <kdebug.h>
+
+Template_ArtsView::Template_ArtsView( QWidget* parent, const char* name ) : QFrame( parent,name ){
+ //kdDebug()<<k_funcinfo<<endl;
+}
+
+Template_ArtsView::~Template_ArtsView() {
+ //kdDebug()<<k_funcinfo<<endl;
+}
+
+void Template_ArtsView::closeEvent( QCloseEvent *e ) {
+ //kdDebug()<<k_funcinfo<<endl;
+ e->accept();
+ emit closed();
+}
+
+#include "templateview.moc"
diff --git a/arts/tools/templateview.h b/arts/tools/templateview.h
new file mode 100644
index 00000000..e101aa85
--- /dev/null
+++ b/arts/tools/templateview.h
@@ -0,0 +1,39 @@
+/*
+
+ Copyright (C) 2003 Arnold Krille <arnold@arnoldarts.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.
+
+ */
+
+#ifndef ARTS_TEMPLATEVIEW_H
+#define ARTS_TEMPLATEVIEW_H
+
+//#include <artsflow.h>
+#include <qframe.h>
+
+class Template_ArtsView : public QFrame
+{
+ Q_OBJECT
+public:
+ Template_ArtsView( QWidget* =0, const char* =0 );
+ ~Template_ArtsView();
+
+ void closeEvent( QCloseEvent* );
+signals:
+ void closed();
+};
+
+#endif