diff --git a/ChangeLog b/ChangeLog index bf222c17b..eaebadb61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,144 @@ +2005-10-19 Tobias Doerffel + + * plugins/vestige/vestige.h: + * plugins/vestige/vestige.cpp: + added possibility of opening plugins instead of hardcoding them ;-) + + * include/track.h: + renamed createTrack() and cloneTrack() to create() and clone() + + * include/track_container.h: + * src/core/track_container.cpp: + receive drop-events -> add channel with instrument/preset + + * src/audio/audio_jack.cpp: + removed usleep() out of loop in audioJACK::writeBufferToDev() since it + caused LMMS to hang e.g when removing a track + + * src/core/plugin_browser.cpp: + show hand-cursor if over a plugin-description-widget + + * src/widgets/pixmap_button.cpp: + if pixmap-button is set non-checkable, draw active-graphic if pressed + down and inactive one in normal state + + * include/lmms_main_win.h: + * src/core/lmms_main_win.cpp: + own workspace for making wheelEvent(...) is now obsolete -> removed + + * include/track_container.h: + * src/core/song_editor.cpp: + * src/core/track_container.cpp: + added own scroll-area for capturing special wheel-events where a + modifier-key (shift, control etc.) is pressed + + * src/core/song_editor.cpp: + removed add-channel-button as it is obsolete after adding plugin-browser + + * resources/: + improved icons such as project_*.png and sample-track-related icons + +2005-10-18 Tobias Doerffel + + * include/channel_track.h: + * src/tracks/channel_track.cpp: + - moved channelButton-implementation to channel_track.src + - added support for receiving drop-events, which makes channel-track + to load either the given instrument or the given preset + + * src/core/plugin_browser.cpp: + * include/plugin_browser.h: + added cool plugin-browser, which displays all available instrument- + plugins which are draggable to a channel-window/button + + * include/string_pair_drag.h: + * src/lib/string_pair_drag.cpp: + added drag'n'drop-implementation for dragging string-pairs (key/value) + which provides a standard-interface, although drag'n'drop has changed a + lot in Qt 4 + + * src/widgets/crystal_button.cpp: + made mouseMoveEvent()-method much more effective + + * Makefile.am: + * buildtools/Makefile.am: + build buildtools in subdir instead of top-build-directory - solves + dependendy problems with bin2res + + * src/core/file_browser.cpp: + do not depend on typeinfo of audioFileProcessor anymore by using + new setParameter()-method + + * include/plugin.h: + added setParameter() and getParameter()-methods for making LMMS able to + set parameters of a specific plugin without knowing anything about it + +2005-10-17 Tobias Doerffel + + * buildtools/bin2res.cpp: + * include/embed.h: + * src/lib/embed.cpp: + - declaration of embedded-data-descriptor is now located in embed.h and + part of namespace embed + - added support for local embedded-resources which is important for + plugins containing their own images etc., so data and access-methods + are stored into namespace PLUGIN_NAME + + * include/plugin.h: + * src/core/plugin.cpp: + added logo-field to descriptor-structure and simplified method for + getting descriptors of all plugins + + * include/basic_filters.h: + removed Moog-2-filter as it is only very CPU-intensive without any + significant difference to sound of normal Moog-filter + +2005-10-16 Tobias Doerffel + + * src/lib/ladspa_manager.cpp: + skip not existing/unreadable directories when searching for plugins + + * include/vestige.h: + * src/plugins/vestige.cpp: + make use of new instrument-play-handle + + * include/channel_track.h: + * src/core/browser.cpp: + * src/core/song_editor.cpp: + * src/midi/midi_file.cpp: + * src/tracks/channel_track.cpp: + renamed loadPlugin() to loadInstrument() + + * include/config_mgr.h: + * src/core/config_mgr.cpp: + added pluginDir()-method + + * include/instrument_play_handle.h: + added another play-handle for playing instruments which do not + produce sound for each note + + * src/plugins/: + renamed directory soundgenerators to plugins and modified all plugins + for working with revised plugin-system + + * include/instrument.h: + * include/plugin.h: + * src/core/instrument.cpp: + * src/core/plugin.cpp: + splitted code from instrument up into class plugin and class instrument + and revised plugin-system + + * include/instrument.h: + * src/core/instrument.cpp: + renamed files soundgenerator.* to instrument.* as well as class-name + +2005-10-15 Tobias Doerffel + + * include/vestige.h: + * src/soundgenerators/vestige.cpp: + new plugin "VeSTige" for handling VST-plugins - VERY experimental, + but at least, we get some sound out of these strange dll-files ;-) + 2005-10-13 Tobias Doerffel * src/audio/audio_jack.cpp: diff --git a/Makefile.am b/Makefile.am index 8ec5213bf..736133edf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,24 +19,23 @@ rpm: $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE).spec endif -noinst_PROGRAMS= bin2res -bin2res_SOURCES = buildtools/bin2res.cpp + +SUBDIRS = artwork buildtools locale midi-maps plugins presets projects samples INCLUDES = -I$(srcdir)/include -I. bin_PROGRAMS = lmms - AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) %.moc: $(srcdir)/include/%.h $(MOC) -o $@ $< - + %.ts: - $(LUPDATE) $(lmms_SOURCES) -ts locale/$@ - + $(LUPDATE) $(lmms_SOURCES) `find plugins/ -type f -name *.cpp` -ts locale/$@ + %.qm: %.ts $(LRELEASE) $< @@ -45,20 +44,18 @@ AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) lmms_MOC = \ ./about_dialog.moc \ ./arp_and_chords_tab_widget.moc \ - ./audio_file_processor.moc \ ./bb_editor.moc \ ./bb_track.moc \ - ./browser.moc \ ./channel_track.moc \ ./config_mgr.moc \ ./crystal_button.moc \ ./envelope_and_lfo_widget.moc \ ./envelope_tab_widget.moc \ ./export_project_dialog.moc \ - ./kmultitabbar.moc \ + ./file_browser.moc \ ./group_box.moc \ + ./kmultitabbar.moc \ ./knob.moc \ - ./ladspa_sine_1063.moc \ ./lcd_spinbox.moc \ ./led_checkbox.moc \ ./lmms_main_win.moc \ @@ -69,6 +66,7 @@ lmms_MOC = \ ./piano_roll.moc \ ./piano_widget.moc \ ./pixmap_button.moc \ + ./plugin_browser.moc \ ./project_notes.moc \ ./rename_dialog.moc \ ./sample_buffer.moc \ @@ -77,7 +75,6 @@ lmms_MOC = \ ./side_bar.moc \ ./side_bar_widget.moc \ ./song_editor.moc \ - ./sound_generator.moc \ ./surround_area.moc \ ./tab_bar.moc \ ./tab_button.moc \ @@ -86,7 +83,6 @@ lmms_MOC = \ ./timeline.moc \ ./track_container.moc \ ./track.moc \ - ./triple_oscillator.moc \ ./visualization_widget.moc @@ -94,8 +90,8 @@ BUILT_SOURCES = $(lmms_MOC) lmms_EMBEDDED_RESOURCES = $(wildcard $(srcdir)/resources/*png AUTHORS COPYING) -./embedded_resources.h: $(lmms_EMBEDDED_RESOURCES) bin2res - $(top_builddir)/bin2res $(lmms_EMBEDDED_RESOURCES) > $@ +./embedded_resources.h: $(lmms_EMBEDDED_RESOURCES) + $(top_builddir)/buildtools/bin2res $(lmms_EMBEDDED_RESOURCES) > $@ ./embed.o: ./embedded_resources.h @@ -113,11 +109,12 @@ lmms_SOURCES = \ $(srcdir)/src/core/about_dialog.cpp \ $(srcdir)/src/core/arp_and_chords_tab_widget.cpp \ $(srcdir)/src/core/bb_editor.cpp \ - $(srcdir)/src/core/browser.cpp \ $(srcdir)/src/core/config_mgr.cpp \ $(srcdir)/src/core/envelope_and_lfo_widget.cpp \ $(srcdir)/src/core/envelope_tab_widget.cpp \ $(srcdir)/src/core/export_project_dialog.cpp \ + $(srcdir)/src/core/file_browser.cpp \ + $(srcdir)/src/core/instrument.cpp \ $(srcdir)/src/core/lmms_main_win.cpp \ $(srcdir)/src/core/main.cpp \ $(srcdir)/src/core/mixer.cpp \ @@ -126,11 +123,12 @@ lmms_SOURCES = \ $(srcdir)/src/core/note_play_handle.cpp \ $(srcdir)/src/core/piano_roll.cpp \ $(srcdir)/src/core/piano_widget.cpp \ + $(srcdir)/src/core/plugin.cpp \ + $(srcdir)/src/core/plugin_browser.cpp \ $(srcdir)/src/core/preset_preview_play_handle.cpp \ $(srcdir)/src/core/sample_play_handle.cpp \ $(srcdir)/src/core/setup_dialog.cpp \ $(srcdir)/src/core/song_editor.cpp \ - $(srcdir)/src/core/sound_generator.cpp \ $(srcdir)/src/core/track.cpp \ $(srcdir)/src/core/track_container.cpp \ $(srcdir)/src/core/surround_area.cpp \ @@ -142,6 +140,7 @@ lmms_SOURCES = \ $(srcdir)/src/lib/mmp.cpp \ $(srcdir)/src/lib/oscillator.cpp \ $(srcdir)/src/lib/sample_buffer.cpp \ + $(srcdir)/src/lib/string_pair_drag.cpp \ $(srcdir)/src/midi/midi_alsa_raw.cpp \ $(srcdir)/src/midi/midi_device.cpp \ $(srcdir)/src/midi/midi_file.cpp \ @@ -189,16 +188,14 @@ lmms_SOURCES = \ $(srcdir)/include/volume.h \ $(srcdir)/include/panning.h \ $(srcdir)/include/song_editor.h \ - $(srcdir)/include/sound_generator.h \ - $(srcdir)/include/audio_file_processor.h \ + $(srcdir)/include/plugin.h \ + $(srcdir)/include/instrument.h \ $(srcdir)/include/midi_time.h \ $(srcdir)/include/bb_editor.h \ $(srcdir)/include/piano_widget.h \ $(srcdir)/include/effect_board.h \ $(srcdir)/include/pixmap_button.h \ - $(srcdir)/include/triple_oscillator.h \ $(srcdir)/include/settings.h \ - $(srcdir)/include/plucked_string_synth.h \ $(srcdir)/include/rename_dialog.h \ $(srcdir)/include/export_project_dialog.h \ $(srcdir)/include/note_play_handle.h \ @@ -214,7 +211,8 @@ lmms_SOURCES = \ $(srcdir)/include/group_box.h \ $(srcdir)/include/tab_widget.h \ $(srcdir)/include/knob.h \ - $(srcdir)/include/browser.h \ + $(srcdir)/include/file_browser.h \ + $(srcdir)/include/plugin_browser.h \ $(srcdir)/include/templates.h \ $(srcdir)/include/gui_templates.h \ $(srcdir)/include/surround_area.h \ @@ -248,7 +246,6 @@ lmms_SOURCES = \ $(srcdir)/include/preset_preview_play_handle.h \ $(srcdir)/include/sample_play_handle.h \ $(srcdir)/include/midi.h \ - $(srcdir)/include/midi_out.h \ $(srcdir)/include/nstate_button.h \ $(srcdir)/include/midi_dummy.h \ $(srcdir)/include/midi_mapper.h \ @@ -259,7 +256,10 @@ lmms_SOURCES = \ $(srcdir)/include/text_float.h \ $(srcdir)/include/tempo_sync_knob.h \ $(srcdir)/include/setup_dialog.h \ - $(srcdir)/include/empty_sg_plugin.h \ + $(srcdir)/include/dummy_plugin.h \ + $(srcdir)/include/dummy_instrument.h \ + $(srcdir)/include/instrument_play_handle.h \ + $(srcdir)/include/string_pair_drag.h \ $(srcdir)/include/ladspa_manager.h @@ -296,18 +296,6 @@ if HAVE_LIBSF LIB_SF_LDADD = -lsndfile endif -lmms_LDADD = $(QT_LDADD) $(LIB_SDL_LDADD) $(LIB_ASOUND_LDADD) $(LIB_JACK_LDADD) $(LIB_SDL_SOUND_LDADD) $(LIB_VORBIS_LDADD) $(LIB_SRC_LDADD) $(LIB_SF_LDADD) -laudiofileprocessor -ldl +lmms_LDADD = $(QT_LDADD) $(LIB_SDL_LDADD) $(LIB_ASOUND_LDADD) $(LIB_JACK_LDADD) $(LIB_SDL_SOUND_LDADD) $(LIB_VORBIS_LDADD) $(LIB_SRC_LDADD) $(LIB_SF_LDADD) -lfst -ldl lmms_LDFLAGS = -rdynamic -rpath $(pkglibdir) -SUBDIRS = artwork locale midi-maps presets projects samples - - - -pkglib_LTLIBRARIES= libaudiofileprocessor.la libsine1063oscillator.la libmidiout.la libpluckedstringsynth.la libtripleoscillator.la - - -libaudiofileprocessor_la_SOURCES = src/soundgenerators/audio_file_processor.cpp -libsine1063oscillator_la_SOURCES = src/soundgenerators/ladspa_sine_1063.cpp -libmidiout_la_SOURCES = src/soundgenerators/midi_out.cpp -libpluckedstringsynth_la_SOURCES = src/soundgenerators/plucked_string_synth.cpp -libtripleoscillator_la_SOURCES = src/soundgenerators/triple_oscillator.cpp diff --git a/README b/README index 46708f92b..8c6932c87 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -Linux MultiMedia Studio 0.1.2 +Linux MultiMedia Studio 0.1.1 ============================== Copyright (c) 2004-2005 by Tobias Doerffel and others @@ -41,13 +41,13 @@ Requirements ------------ The most important requirement is for sure a fast computer, so don't try to get -LMMS working on a pentium I with 60 MHz... ;-) So you should have at least -500 MHz, but for really enjoying LMMS less than 1 GHz makes no sense... -(LMMS is currently developed on a PIII 450 MHz...!!) +LMMS working on a pentium I with 60 MHz... ;-) Therefore you should have at +least 500 MHz, but for really enjoying LMMS less than 1 GHz makes no sense... + Required libraries are: -- Qt 3.2 or higher (tested up to 4.0.0) with devel-files +- Qt 3.0 (3.2 recommended) or higher (tested up to 4.0.0) with devel-files Optional, but strongly recommended: - libvorbis with devel-files @@ -57,6 +57,7 @@ Optional, but strongly recommended: - libsamplerate with devel-files - libsndfile with devel-files - JACK with devel-files +- libfst + header-files from Steinberg SDK For compiling you should have an up to date GCC with g++. LMMS has been (successfully) tested under Debian Sarge 3.1, Fedora Core 2-4, @@ -83,16 +84,16 @@ can be found at http://lmms.sourceforge.net -Before coding a new big feature, please always post your idea and suggestions +Details on development can be found at + +http://lmms.sourceforge.net/development.php + +or in the Wiki: + +http://wiki.mindrules.net + +Before coding a new big feature, please ALWAYS post your idea and suggestions about your feature and about the actual implementation to the LMMS-devel-mailinglist (lmms-devel@lists.sourceforge.net) and wait for replies! Maybe there're different ideas, improvements, hints or maybe your feature is not welcome/needed at the moment (but for sure this will be very seldom). - -If you coded your feature, make sure, that it is running properly with the -newest available version of LMMS and that it also runs with different -configurations (e.g. disabled surround-support, missing package(s) etc.). -Important is also, that you comment your source so that other people can fix -bugs or improve your feature! - - diff --git a/TODO b/TODO index d97492ddd..75a0d9146 100644 --- a/TODO +++ b/TODO @@ -1,18 +1,20 @@ -- toolbar-redesign in song-editor, bb-editor and piano-roll!!! -- addchannel-toolbutton -> popup-menu with available soundgenerator-plugins +- complete toolbar-redesign in song-editor, bb-editor and piano-roll!!! +- dnd everywhere: presets, samples (afp/sample-track), TCO's, knob-values +- save/load parameters of VST-plugin +- move VST-code into separate class which can use several backends (libfst, dssi-vst and vst-server) -> add libfst/dssi-vst/vstserver-check to configure.in +- somehow avoid hidden plugin-descriptor-widgets if height of window is too small -> add scrollbar +- use drawLineF() for drawing notes in pattern::paintEvent() in qt4-version +- pattern freeze -> do not endless loop if looping-points are enabled - solve problem with knob-control-precision -- built-in VST-support -- proper dlclos()ing of sg-plugins -- use own scrollview for capturing wheel-events - add note-len- and note-alignment-selectbox to piano-roll - only redraw region given by paint-event in pattern, bbTCO, sampleTCO etc. - make LMMS an ALSA-sequencer-client + - use midi-maps + - process program-/channel-change-events from MIDI-files + - setup MIDI-channel and -program in MIDI-Out - pre-listen when opening sample with QFileDialog - level-meters in output-graph and channel-track - panning-editing in piano-roll -- use midi-maps -- process program-/channel-change-events from MIDI-files -- setup MIDI-channel and -program in MIDI-Out - speed up painting of sampleTCO - save window-positions, -states and -sizes in files - solve problems with different keyboard-layouts when playing channel-track with pc-keyboard -> use tr() diff --git a/buildtools/Makefile.am b/buildtools/Makefile.am new file mode 100644 index 000000000..78630dc92 --- /dev/null +++ b/buildtools/Makefile.am @@ -0,0 +1,5 @@ +AUTOMAKE_OPTIONS = foreign 1.4 + +noinst_PROGRAMS= bin2res +bin2res_SOURCES = bin2res.cpp + diff --git a/buildtools/bin2res.cpp b/buildtools/bin2res.cpp index 9680c699c..4570096d9 100644 --- a/buildtools/bin2res.cpp +++ b/buildtools/bin2res.cpp @@ -97,7 +97,7 @@ int main( int argc, char * * argv ) e->cname = convertFileNameToCIdentifier( e->name ); embedded_data.push_back( e ); std::string s; - std::cout << "static const unsigned char " << e->cname << + std::cout << "const unsigned char " << e->cname << "_data[] = {"; embedData( data, fsize, std::cout ); std::cout << std::endl << "};" << std::endl << std::endl; @@ -106,7 +106,7 @@ int main( int argc, char * * argv ) if( embedded_data.size() > 0 ) { - std::cout << "static const unsigned char dummy_data[] =" + std::cout << "const unsigned char dummy_data[] =" "{ 0x00 };" << std::endl << std::endl; embed * dummy = new embed; dummy->size = 1; @@ -114,14 +114,15 @@ int main( int argc, char * * argv ) dummy->cname = convertFileNameToCIdentifier( "dummy" ); embedded_data.push_back( dummy ); - std::cout << "#include " << std::endl; - std::cout << "static struct embedDesc" << std::endl - << "{" << std::endl + std::cout << "#include " << std::endl << std::endl; + std::cout << "#include \"embed.h\"" << std::endl << std::endl; + std::cout << "embed::descriptor embed_vec[] = {" << std::endl; +/* << "{" << std::endl << " int size;" << std::endl << " const unsigned char * data;" << std::endl << " const char * name;" << std::endl - << "} embed_vec[] = {" << std::endl; + << "} embed_vec[] = {" << std::endl;*/ while( embedded_data.size() > 0 ) { embed * e = embedded_data[0]; @@ -133,9 +134,9 @@ int main( int argc, char * * argv ) } std::cout << " { 0, 0, 0 }" << std::endl << "};" << std::endl << std::endl - << "static const embedDesc & findEmbeddedData( " - "const char * _name )" << std::endl - << "{" << std::endl + << "const embed::descriptor & " + "findEmbeddedData( const char * _name )" + << std::endl << "{" << std::endl << " for( int i = 0; embed_vec[i].data; " "i++ )" << std::endl << " {" << std::endl diff --git a/configure.in b/configure.in index 31ed5a8d2..b2cafdf18 100644 --- a/configure.in +++ b/configure.in @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) -AC_INIT(lmms, 0.1.1-cvs20051013, tobydox@users.sourceforge.net) -AM_INIT_AUTOMAKE(lmms, 0.1.1-cvs20051013) +AC_INIT(lmms, 0.1.1-cvs20051019, tobydox@users.sourceforge.net) +AM_INIT_AUTOMAKE(lmms, 0.1.1-cvs20051019) AM_CONFIG_HEADER(config.h) @@ -22,7 +22,7 @@ gw_CHECK_QT # checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([fcntl.h memory.h string.h sys/ioctl.h unistd.h stdlib.h dlfcn.h]) +AC_CHECK_HEADERS([fcntl.h memory.h string.h sys/ioctl.h unistd.h stdlib.h dlfcn.h ladspa.h]) # checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -349,14 +349,23 @@ fi AC_CONFIG_FILES([Makefile artwork/Makefile + buildtools/Makefile locale/Makefile midi-maps/Makefile + plugins/Makefile + plugins/audio_file_processor/Makefile + plugins/ladspa_sine_1063/Makefile + plugins/midi_out/Makefile + plugins/plucked_string_synth/Makefile + plugins/triple_oscillator/Makefile + plugins/vestige/Makefile presets/Makefile presets/AudioFileProcessor/Makefile presets/MIDI-Out/Makefile presets/PluckedStringSynth/Makefile presets/Sine1063Oscillator/Makefile presets/TripleOscillator/Makefile + presets/VeSTige/Makefile projects/Makefile projects/cool_songs/Makefile projects/covers/Makefile diff --git a/include/audio_alsa.h b/include/audio_alsa.h index 0604724e2..aa4cdf808 100644 --- a/include/audio_alsa.h +++ b/include/audio_alsa.h @@ -80,7 +80,7 @@ public: private: virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ); + float _master_gain ); int FASTCALL setHWParams( Uint32 _sample_rate, Uint32 _channels, snd_pcm_access_t _access ); diff --git a/include/audio_device.h b/include/audio_device.h index 28f612e07..0bf7dd980 100644 --- a/include/audio_device.h +++ b/include/audio_device.h @@ -68,7 +68,7 @@ public: void FASTCALL writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, Uint32 _src_sample_rate, - float _master_output ); + float _master_gain ); inline Uint32 sampleRate( void ) const { @@ -104,12 +104,12 @@ public: protected: virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ) = 0; + float _master_gain ) = 0; // convert a given audio-buffer to a buffer in signed 16-bit samples // returns num of bytes in outbuf int FASTCALL convertToS16( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output, + float _master_gain, outputSampleType * _output_buffer, bool _convert_endian = FALSE ); diff --git a/include/audio_file_ogg.h b/include/audio_file_ogg.h index 2a1ae256c..9ab234932 100644 --- a/include/audio_file_ogg.h +++ b/include/audio_file_ogg.h @@ -64,7 +64,7 @@ public: private: virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ); + float _master_gain ); bool startEncoding( void ); void finishEncoding( void ); diff --git a/include/audio_file_wave.h b/include/audio_file_wave.h index c8e95a033..61358a0e9 100644 --- a/include/audio_file_wave.h +++ b/include/audio_file_wave.h @@ -57,7 +57,7 @@ public: private: virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ); + float _master_gain ); bool startEncoding( void ); void finishEncoding( void ); diff --git a/include/audio_jack.h b/include/audio_jack.h index df7eaa943..4b33b79eb 100644 --- a/include/audio_jack.h +++ b/include/audio_jack.h @@ -91,7 +91,7 @@ public: private: virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ); + float _master_gain ); void clearBuffer( void ); diff --git a/include/audio_oss.h b/include/audio_oss.h index 49c8bcf6b..443a2bcd4 100644 --- a/include/audio_oss.h +++ b/include/audio_oss.h @@ -75,7 +75,7 @@ public: private: virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ); + float _master_gain ); int m_audioFD; diff --git a/include/audio_sample_recorder.h b/include/audio_sample_recorder.h index 8bbfc47d0..31a2af9cc 100644 --- a/include/audio_sample_recorder.h +++ b/include/audio_sample_recorder.h @@ -63,7 +63,7 @@ public: private: virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ); + float _master_gain ); typedef vvector > bufferVector; bufferVector m_buffers; diff --git a/include/audio_sdl.h b/include/audio_sdl.h index 1f8670252..6c6cf890a 100644 --- a/include/audio_sdl.h +++ b/include/audio_sdl.h @@ -88,7 +88,7 @@ public: private: virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ); + float _master_gain ); void clearBuffer( void ); diff --git a/include/basic_filters.h b/include/basic_filters.h index 5f6bbf306..7d02c0efd 100644 --- a/include/basic_filters.h +++ b/include/basic_filters.h @@ -54,11 +54,9 @@ public: NOTCH, ALLPASS, MOOG, - MOOG2, SIMPLE_FLT_CNT, DOUBLE_LOWPASS = 16+LOWPASS, - DOUBLE_MOOG = 16+MOOG, - DOUBLE_MOOG2 = 16+MOOG2 + DOUBLE_MOOG = 16+MOOG } ; static inline filterTypes getFilterType( const int _idx ) @@ -127,7 +125,7 @@ public: m_y4[_chnl] * ( 1.0f / 6.0f ); break; } - case MOOG2: +/* case MOOG2: case DOUBLE_MOOG2: { const float x1 = ( _in0 - m_r * @@ -190,7 +188,7 @@ public: out = m_oldx[_chnl]; break; - } + }*/ default: // filter @@ -251,7 +249,7 @@ public: break; } - case DOUBLE_MOOG2: +/* case DOUBLE_MOOG2: { if( m_subFilter == NULL ) { @@ -276,7 +274,7 @@ public: kfcr * kf ) ); m_r = 4 * _q * kacr; break; - } + }*/ default: { diff --git a/include/bb_editor.h b/include/bb_editor.h index eea12f814..f3d4b46b8 100644 --- a/include/bb_editor.h +++ b/include/bb_editor.h @@ -83,10 +83,10 @@ public: protected: - void closeEvent( QCloseEvent * _ce ); - void keyPressEvent (QKeyEvent * _ke); - void wheelEvent( QWheelEvent * _we ); - void resizeEvent( QResizeEvent * _re ); + virtual void closeEvent( QCloseEvent * _ce ); + virtual void keyPressEvent( QKeyEvent * _ke ); + virtual void resizeEvent( QResizeEvent * _re ); + void updateBackground( void ); diff --git a/include/config_mgr.h b/include/config_mgr.h index 0143aac28..89afa1444 100644 --- a/include/config_mgr.h +++ b/include/config_mgr.h @@ -105,6 +105,11 @@ public: { return( m_lmmsDataDir + LOCALE_PATH ); } + const QString & pluginDir( void ) const + { + return( m_lmmsPluginDir ); + } + const QString & value( const QString & _class, const QString & _attribute ) const; @@ -148,6 +153,7 @@ private: const QString m_lmmsRcFile; QString m_lmmsWorkingDir; QString m_lmmsDataDir; + QString m_lmmsPluginDir; typedef vvector > stringPairVector; typedef QMap settingsMap; diff --git a/include/dummy_instrument.h b/include/dummy_instrument.h new file mode 100644 index 000000000..c8af94104 --- /dev/null +++ b/include/dummy_instrument.h @@ -0,0 +1,61 @@ +/* + * dummy_instrument.h - instrument used as fallback if an instrument couldn't + * be loaded + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _DUMMY_INSTRUMENT_H +#define _DUMMY_INSTRUMENT_H + +#include "instrument.h" + + +class dummyInstrument : public instrument +{ +public: + inline dummyInstrument( channelTrack * _channel_track ) : + instrument( _channel_track, "Dummy instrument" ) + { + } + + inline virtual ~dummyInstrument() + { + } + + + inline virtual void saveSettings( QDomDocument &, QDomElement & ) + { + } + + inline virtual void loadSettings( const QDomElement & ) + { + } + + inline virtual QString nodeName( void ) const + { + return( "dummyinstrument" ); + } + +} ; + + +#endif diff --git a/include/dummy_plugin.h b/include/dummy_plugin.h new file mode 100644 index 000000000..f84e44af4 --- /dev/null +++ b/include/dummy_plugin.h @@ -0,0 +1,61 @@ +/* + * dummy_plugin.h - empty plugin which is used as fallback if a plugin wasn't + * found + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _DUMMY_PLUGIN_H +#define _DUMMY_PLUGIN_H + +#include "plugin.h" + + +class dummyPlugin : public plugin +{ +public: + inline dummyPlugin( void ) : + plugin( "Dummy plugin", plugin::UNDEFINED ) + { + } + + inline virtual ~dummyPlugin() + { + } + + + inline virtual void saveSettings( QDomDocument &, QDomElement & ) + { + } + + inline virtual void loadSettings( const QDomElement & ) + { + } + + inline virtual QString nodeName( void ) const + { + return( "dummyplugin" ); + } + +} ; + + +#endif diff --git a/include/embed.h b/include/embed.h index 314c8ccd4..1fb6878d7 100644 --- a/include/embed.h +++ b/include/embed.h @@ -42,10 +42,31 @@ namespace embed { +struct descriptor +{ + int size; + const unsigned char * data; + const char * name; +} ; + + QPixmap getIconPixmap( const char * _name, int _w = -1, int _h = -1 ); QString getText( const char * _name ); void loadTranslation( const QString & _tname ); } + +#ifdef PLUGIN_NAME +namespace PLUGIN_NAME +{ + +QPixmap getIconPixmap( const char * _name, int _w = -1, int _h = -1 ); +QString getText( const char * _name ); +void loadTranslation( const QString & _tname ); + +} +#endif + + #endif diff --git a/include/ladspa_manager.h b/include/ladspa_manager.h index c514e3453..12c917bc5 100644 --- a/include/ladspa_manager.h +++ b/include/ladspa_manager.h @@ -31,6 +31,12 @@ #include #endif +#ifdef HAVE_LADSPA_H + +#define LADSPA_SUPPORT + +#include + #include "qt3support.h" #ifdef QT4 @@ -49,9 +55,10 @@ #endif -#include + #include "types.h" + typedef QPair ladspaKey; /* ladspaManager provides a database of LADSPA plug-ins. Upon instantiation, @@ -188,7 +195,7 @@ public: /* The following methods are convenience functions for use during - development. A real soundGenerator should use the getDescriptor() + development. A real instrument should use the getDescriptor() method and implement the plug-in manipulations internally to avoid the overhead associated with QMap lookups. */ @@ -326,5 +333,7 @@ private: typedef QMap ladspaManagerMapType; ladspaManagerMapType m_ladspaManagerMap; }; - + +#endif + #endif diff --git a/include/mixer.h b/include/mixer.h index 0a2353751..b6d52dfa1 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -57,6 +57,7 @@ class audioDevice; class midiDevice; class lmmsMainWin; +class plugin; const int DEFAULT_BUFFER_SIZE = 512; @@ -174,7 +175,8 @@ public: m_playHandlesToRemove.push_back( _ph ); } - void FASTCALL checkValidityOfPlayHandles( void ); + void checkValidityOfPlayHandles( void ); + inline int sampleRate( void ) @@ -319,7 +321,6 @@ private: volatile bool m_quit; - audioDevice * m_audioDev; audioDevice * m_oldAudioDev; QString m_audioDevName; diff --git a/include/plugin.h b/include/plugin.h new file mode 100644 index 000000000..95daa74d0 --- /dev/null +++ b/include/plugin.h @@ -0,0 +1,133 @@ +/* + * plugin.h - class plugin, the base-class and generic interface for all plugins + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _PLUGIN_H +#define _PLUGIN_H + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include + +#else + +#include +#include + +#endif + + +#include "types.h" +#include "settings.h" +#include "embed.h" + + +#define STRINGIFY_PLUGIN_NAME(s) STR(s) +#define STR(PN) #PN + + +class QPixmap; + + +class plugin : public settings +{ +public: + enum pluginTypes + { + INSTRUMENT, // instrument being used in channel-track + EFFECT, // effect-plugin for effect-board + IMPORT_FILTER, // filter for importing a file + EXPORT_FILTER, // filter for exporting a file + UNDEFINED = 255 + } ; + + // descriptor holds information about a plugin - every external plugin + // has to instantiate such a descriptor in an extern "C"-section so that + // the plugin-loader is able to access information about the plugin + struct descriptor + { + const char * name; + const char * public_name; + const char * description; + const char * author; + int version; + pluginTypes type; + embed::descriptor logo; + } ; + + // contructor of a plugin + // _name: public name of plugin + // _type: one of the plugin-types defined above + plugin( const QString & _public_name, pluginTypes _type ); + virtual ~plugin(); + + // returns the name, the plugin passed to plugin-constructor + inline const QString & publicName( void ) const + { + return( m_publicName ); + } + + // return type + inline pluginTypes type( void ) const + { + return( m_type ); + } + + // plugins can overload this for making other classes able to change + // settings of the plugin without knowing the actual class + virtual void FASTCALL setParameter( const QString & _param, + const QString & _value ); + + // plugins can overload this for making other classes able to query + // settings of the plugin without knowing the actual class + virtual QString FASTCALL getParameter( const QString & _param ); + + + // returns an instance of a plugin whose name matches to given one + // if specified plugin couldn't be loaded, it creates a dummy-plugin + static plugin * FASTCALL instantiate( const QString & _plugin_name, + void * _data ); + + // fills given vector with descriptors for all available plugins + static void FASTCALL getDescriptorsOfAvailPlugins( + vvector & _plugin_descs ); + +private: + const QString m_publicName; + const pluginTypes m_type; + + // pointer to instantiation-function in plugin + typedef plugin * ( * instantiationHook )( void * ); + +} ; + + +#endif diff --git a/include/plugin_browser.h b/include/plugin_browser.h new file mode 100644 index 000000000..066c6a834 --- /dev/null +++ b/include/plugin_browser.h @@ -0,0 +1,96 @@ +/* + * plugin_browser.h - include file for pluginBrowser + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _PLUGIN_BROWSER_H +#define _PLUGIN_BROWSER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include + +#else + +#include +#include + +#endif + + +#include "side_bar_widget.h" +#include "plugin.h" + + +class trackContainer; + + +class pluginBrowser : public sideBarWidget +{ + Q_OBJECT +public: + pluginBrowser( QWidget * _parent ); + virtual ~pluginBrowser(); + + +private: + vvector m_pluginDescriptors; + + QWidget * m_view; + +} ; + + + + +class pluginDescWidget : public QWidget +{ +public: + pluginDescWidget( const plugin::descriptor & _pd, QWidget * _parent ); + virtual ~pluginDescWidget(); + + +protected: + virtual void paintEvent( QPaintEvent * _pe ); + virtual void mousePressEvent( QMouseEvent * _me ); + virtual void mouseMoveEvent( QMouseEvent * _me ); + virtual void mouseReleaseEvent( QMouseEvent * _me ); + + +private: + const plugin::descriptor & m_pluginDescriptor; + QPixmap m_logo; + + bool m_mouseOver; + +} ; + + +#endif diff --git a/include/side_bar_widget.h b/include/side_bar_widget.h index 11032a954..ba059790c 100644 --- a/include/side_bar_widget.h +++ b/include/side_bar_widget.h @@ -48,7 +48,7 @@ class sideBarWidget : public QWidget public: sideBarWidget( const QString & _title, const QPixmap & _icon, QWidget * _parent ); - ~sideBarWidget(); + virtual ~sideBarWidget(); inline const QPixmap & icon( void ) const { return( m_icon ); @@ -60,9 +60,9 @@ public: protected: - void paintEvent( QPaintEvent * _pe ); - void resizeEvent( QResizeEvent * _re ); - inline void contextMenuEvent( QContextMenuEvent * ) + virtual void paintEvent( QPaintEvent * _pe ); + virtual void resizeEvent( QResizeEvent * _re ); + inline virtual void contextMenuEvent( QContextMenuEvent * ) { } diff --git a/include/song_editor.h b/include/song_editor.h index ea55094cb..3bfc8e00c 100644 --- a/include/song_editor.h +++ b/include/song_editor.h @@ -229,7 +229,6 @@ protected: protected slots: void insertTact( void ); void removeTact( void ); - void addChannelTrack( void ); void addBBTrack( void ); void addSampleTrack( void ); void scrolled( int _new_pos ); diff --git a/include/string_pair_drag.h b/include/string_pair_drag.h new file mode 100644 index 000000000..41b3df102 --- /dev/null +++ b/include/string_pair_drag.h @@ -0,0 +1,64 @@ +/* + * string_pair_drag.h - class stringPairDrag which provides general support + * for drag'n'drop of string-pairs + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef _STRING_PAIR_DRAG_H +#define _STRING_PAIR_DRAG_H + +#include "qt3support.h" + +#ifdef QT4 + +#include + +#else + +#include + +#endif + + +class QPixmap; + + +class stringPairDrag : public +#ifdef QT4 + QDrag +#else + QStoredDrag +#endif +{ +public: + stringPairDrag( const QString & _key, const QString & _value, + const QPixmap & _icon, QWidget * _w ); + ~stringPairDrag(); + + static void processDragEnterEvent( QDragEnterEvent * _dee, + const QString & _allowed_keys ); + static QString decodeKey( QDropEvent * _de ); + static QString decodeValue( QDropEvent * _de ); + +} ; + + +#endif diff --git a/include/track.h b/include/track.h index 39e2605b8..1245884ed 100644 --- a/include/track.h +++ b/include/track.h @@ -227,7 +227,7 @@ public: public slots: void changePosition( const midiTime & _new_pos = -1 ); void cloneTrack( void ); - void deleteTrack( void ); + void removeTrack( void ); void moveTrackUp( void ); void moveTrackDown( void ); void setMuted( bool _muted ); @@ -271,11 +271,10 @@ public: track( trackContainer * _tc ); virtual ~track(); - static track * FASTCALL createTrack( trackTypes _tt, + static track * FASTCALL create( trackTypes _tt, trackContainer * _tc ); + static track * FASTCALL create( const QDomElement & _this, trackContainer * _tc ); - static track * FASTCALL createTrack( const QDomElement & _this, - trackContainer * _tc ); - static track * FASTCALL cloneTrack( track * _track ); + static track * FASTCALL clone( track * _track ); tact length( void ) const; diff --git a/include/track_container.h b/include/track_container.h index 985f80d23..9ddd6fcce 100644 --- a/include/track_container.h +++ b/include/track_container.h @@ -93,10 +93,13 @@ public: protected: + virtual void resizeEvent( QResizeEvent * ); + virtual void dragEnterEvent( QDragEnterEvent * _dee ); + virtual void dropEvent( QDropEvent * _de ); + constTrackVector tracks( void ) const; trackVector tracks( void ); - virtual void resizeEvent( QResizeEvent * ); midiTime m_currentPosition; @@ -106,16 +109,33 @@ protected slots: private: - QScrollArea * m_scrollArea; + + class scrollArea : public QScrollArea + { + public: + scrollArea( trackContainer * _parent ); + virtual ~scrollArea(); + + protected: + virtual void wheelEvent( QWheelEvent * _we ); + + } ; + + + scrollArea * m_scrollArea; typedef vvector trackWidgetVector; trackWidgetVector m_trackWidgets; float m_ppt; + friend class scrollArea; + + signals: void positionChanged( const midiTime & _pos ); + } ; diff --git a/include/volume.h b/include/volume.h index dc37abd48..640c349d3 100644 --- a/include/volume.h +++ b/include/volume.h @@ -1,5 +1,6 @@ /* - * volume.h - declaration of some constants and types, concerning the volume of a note + * volume.h - declaration of some constants and types, concerning the volume + * of a note * * Linux MultiMedia Studio * Copyright (c) 2004-2005 Tobias Doerffel diff --git a/plugins/Makefile.am b/plugins/Makefile.am new file mode 100644 index 000000000..cd149a68c --- /dev/null +++ b/plugins/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = audio_file_processor ladspa_sine_1063 midi_out plucked_string_synth triple_oscillator vestige + diff --git a/plugins/audio_file_processor/Makefile.am b/plugins/audio_file_processor/Makefile.am new file mode 100644 index 000000000..3c8af8bc5 --- /dev/null +++ b/plugins/audio_file_processor/Makefile.am @@ -0,0 +1,34 @@ +AUTOMAKE_OPTIONS = foreign 1.4 + + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I. + + +AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="audiofileprocessor" + + +%.moc: ./%.h + $(MOC) -o $@ $< + + +MOC_FILES = ./audio_file_processor.moc + +BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h + +EMBEDDED_RESOURCES = $(wildcard *png) + +./embedded_resources.h: $(EMBEDDED_RESOURCES) + $(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@ + +EXTRA_DIST = $(EMBEDDED_RESOURCES) + + +CLEANFILES = $(MOC_FILES) ./embedded_resources.h + + + +pkglib_LTLIBRARIES= libaudiofileprocessor.la + +libaudiofileprocessor_la_SOURCES = audio_file_processor.cpp audio_file_processor.h + +$(libaudiofileprocessor_la_SOURCES): ./embedded_resources.h diff --git a/plugins/audio_file_processor/artwork.png b/plugins/audio_file_processor/artwork.png new file mode 100644 index 000000000..6b980c233 Binary files /dev/null and b/plugins/audio_file_processor/artwork.png differ diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp new file mode 100644 index 000000000..8cc9de7fc --- /dev/null +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -0,0 +1,628 @@ +/* + * audio_file_processor.cpp - instrument for using audio-files + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +#include +#include +#include + +#else + +#include +#include +#include +#include +#include + +#define isChecked isOn +#define setChecked setOn + +#endif + + +#include "audio_file_processor.h" +#include "song_editor.h" +#include "channel_track.h" +#include "note_play_handle.h" +#include "paths.h" +#include "interpolation.h" +#include "buffer_allocator.h" +#include "pixmap_button.h" +#include "knob.h" +#include "tooltip.h" + +#include "embed.cpp" + + + +extern "C" +{ + +plugin::descriptor audiofileprocessor_plugin_descriptor = +{ + STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ), + "AudioFileProcessor", + QT_TRANSLATE_NOOP( "plugin", + "simple sampler with various settings for " + "using samples (e.g. drums) in a channel" ), + "Tobias Doerffel ", + 0x0100, + plugin::INSTRUMENT, + PLUGIN_NAME::findEmbeddedData( "logo.png" ) +} ; + +} + + +QPixmap * audioFileProcessor::s_artwork = NULL; + + + +audioFileProcessor::audioFileProcessor( channelTrack * _channel_track ) : + instrument( _channel_track, + audiofileprocessor_plugin_descriptor.public_name ), + specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ), + m_sampleBuffer( "" ), + m_drawMethod( sampleBuffer::LINE_CONNECT ) +{ + connect( &m_sampleBuffer, SIGNAL( sampleUpdated() ), this, + SLOT( sampleUpdated() ) ); + + if( s_artwork == NULL ) + { + s_artwork = new QPixmap( PLUGIN_NAME::getIconPixmap( + "artwork" ) ); + } + + + m_openAudioFileButton = new pixmapButton( this ); + m_openAudioFileButton->setCheckable( FALSE ); + m_openAudioFileButton->setCursor( QCursor( Qt::PointingHandCursor ) ); + m_openAudioFileButton->move( 200, 90 ); + m_openAudioFileButton->setActiveGraphic( embed::getIconPixmap( + "project_open_down" ) ); + m_openAudioFileButton->setInactiveGraphic( embed::getIconPixmap( + "project_open" ) ); + m_openAudioFileButton->setBgGraphic( getBackground( + m_openAudioFileButton ) ); + connect( m_openAudioFileButton, SIGNAL( clicked() ), this, + SLOT( openAudioFile() ) ); + toolTip::add( m_openAudioFileButton, tr( "Open other sample" ) ); + +#ifdef QT4 + m_openAudioFileButton->setWhatsThis( +#else + QWhatsThis::add( m_openAudioFileButton, +#endif + tr( "Click here, if you want to open another audio-file. After " + "clicking on this button, a file-open-dialog appears " + "and you can select your file. Settings like Looping-" + "Mode, start- and end-point, amplify-value and so on " + "are not reset, so please don't wonder if your sample " + "doesn't sound like the original one..." ) ); + + m_reverseButton = new pixmapButton( this ); + m_reverseButton->move( 160, 124 ); + m_reverseButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "reverse_on" ) ); + m_reverseButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "reverse_off" ) ); + m_reverseButton->setBgGraphic( getBackground( m_reverseButton ) ); + connect( m_reverseButton, SIGNAL( toggled( bool ) ), this, + SLOT( reverseBtnToggled( bool ) ) ); + toolTip::add( m_reverseButton, tr( "Reverse sample" ) ); +#ifdef QT4 + m_reverseButton->setWhatsThis( +#else + QWhatsThis::add( m_reverseButton, +#endif + tr( "If you enable this button, the whole sample is reversed. " + "This is useful for cool effects, e.g. a reversed " + "crash." ) ); + + m_loopButton = new pixmapButton( this ); + m_loopButton->move( 180, 124 ); + m_loopButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "loop_on" ) ); + m_loopButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "loop_off" ) ); + m_loopButton->setBgGraphic( getBackground( m_loopButton ) ); + toolTip::add( m_loopButton, + tr( "Loop sample at start- and end-point" ) ); +#ifdef QT4 + m_loopButton->setWhatsThis( +#else + QWhatsThis::add( m_loopButton, +#endif + tr( "Here you can set, whether Looping-Mode is enabled. If " + "enabled, AudioFileProcessor loops between start- and " + "end-point of a sample until the whole note is played. " + "This is useful for things like string- and choir-" + "samples." ) ); + + m_ampKnob = new knob( knobDark_28, this, tr( "Amplify" ) ); + m_ampKnob->setRange( 0, 500, 1.0f ); + m_ampKnob->move( 6, 114 ); + m_ampKnob->setValue( 100.0f, TRUE ); + m_ampKnob->setHintText( tr( "Amplify:" )+" ", "%" ); + m_ampKnob->setLabel( tr( "AMP" ) ); + connect( m_ampKnob, SIGNAL( valueChanged( float ) ), this, + SLOT( ampKnobChanged( float ) ) ); +#ifdef QT4 + m_ampKnob->setWhatsThis( +#else + QWhatsThis::add( m_ampKnob, +#endif + tr( "With this knob you can set the amplify-ratio. When you " + "set a value of 100% your sample isn't changed. " + "Otherwise it will be amplified up or down (your " + "actual sample-file isn't touched!)" ) ); + + m_startKnob = new knob( knobDark_28, this, tr( "Start of sample" ) ); + m_startKnob->setRange( 0, 1.0, 0.00001 ); + m_startKnob->move( 46, 114 ); + m_startKnob->setValue( 0.0, TRUE ); + m_startKnob->setHintText( tr( "Startpoint:" )+" ", "" ); + m_startKnob->setLabel( tr( "START" ) ); + connect( m_startKnob, SIGNAL( valueChanged( float ) ), this, + SLOT( startKnobChanged( float ) ) ); +#ifdef QT4 + m_startKnob->setWhatsThis( +#else + QWhatsThis::add( m_startKnob, +#endif + tr( "With this knob you can set the point where " + "AudioFileProcessor should begin playing your sample. " + "If you enable Looping-Mode, this is the point to " + "which AudioFileProcessor returns if a note is longer " + "than the sample between start- and end-point." ) ); + + m_endKnob = new knob( knobDark_28, this, tr( "End of sample" ) ); + m_endKnob->setRange( 0, 1.0, 0.00001 ); + m_endKnob->move( 84, 114 ); + m_endKnob->setValue( 1.0, TRUE ); + m_endKnob->setHintText( tr( "Endpoint:" )+" ", "" ); + m_endKnob->setLabel( tr( "END" ) ); + connect( m_endKnob, SIGNAL( valueChanged( float ) ), this, + SLOT( endKnobChanged( float ) ) ); +#ifdef QT4 + m_endKnob->setWhatsThis( +#else + QWhatsThis::add( m_endKnob, +#endif + tr( "With this knob you can set the point where " + "AudioFileProcessor should stop playing your sample. " + "If you enable Looping-Mode, this is the point where " + "AudioFileProcessor returns if a note is longer than " + "the sample between start- and end-point." ) ); + + m_viewLinesPB = new pixmapButton( this ); + m_viewLinesPB->move( 154, 158 ); + m_viewLinesPB->setBgGraphic( getBackground( m_viewLinesPB ) ); + if( m_drawMethod == sampleBuffer::LINE_CONNECT ) + { +#ifdef QT4 + m_viewLinesPB->setChecked( TRUE ); +#else + m_viewLinesPB->setOn( TRUE ); +#endif + } + connect( m_viewLinesPB, SIGNAL( toggled( bool ) ), this, + SLOT( lineDrawBtnToggled( bool ) ) ); +#ifdef QT4 + m_viewLinesPB->setWhatsThis( +#else + QWhatsThis::add( m_viewLinesPB, +#endif + tr( "Activate this button, if your sample should be drawn " + "with connected lines. This doesn't change the " + "sound itself. It just gives you another view to your " + "sample." ) ); + + m_viewDotsPB = new pixmapButton( this ); + m_viewDotsPB->move( 204, 158 ); + m_viewDotsPB->setBgGraphic( getBackground( m_viewDotsPB ) ); + if( m_drawMethod == sampleBuffer::DOTS ) + { +#ifdef QT4 + m_viewDotsPB->setChecked( TRUE ); +#else + m_viewDotsPB->setOn( TRUE ); +#endif + } + connect( m_viewDotsPB, SIGNAL( toggled( bool ) ), this, + SLOT( dotDrawBtnToggled( bool ) ) ); +#ifdef QT4 + m_viewDotsPB->setWhatsThis( +#else + QWhatsThis::add( m_viewDotsPB, +#endif + tr( "Activate this button, if your sample should be drawn " + "with dots. This doesn't change the sound itself. " + "It just gives you another view to your sample." ) ); + + QButtonGroup * view_group = new QButtonGroup( this ); + view_group->addButton( m_viewLinesPB ); + view_group->addButton( m_viewDotsPB ); + view_group->setExclusive( TRUE ); +#ifndef QT4 + view_group->hide(); + + setBackgroundMode( Qt::NoBackground ); +#endif +} + + + + +audioFileProcessor::~audioFileProcessor() +{ +} + + + + +void audioFileProcessor::saveSettings( QDomDocument & _doc, + QDomElement & _parent ) +{ + QDomElement afp_de = _doc.createElement( nodeName() ); + afp_de.setAttribute( "src", m_sampleBuffer.audioFile() ); + afp_de.setAttribute( "sframe", QString::number( + m_sampleBuffer.startFrame() / + (float)m_sampleBuffer.frames() ) ); + afp_de.setAttribute( "eframe", QString::number( + m_sampleBuffer.endFrame() / + (float)m_sampleBuffer.frames() ) ); + afp_de.setAttribute( "reversed", QString::number( + m_reverseButton->isChecked() ) ); + afp_de.setAttribute( "looped", QString::number( + m_loopButton->isChecked() ) ); + afp_de.setAttribute( "amp", QString::number( m_ampKnob->value() ) ); + _parent.appendChild( afp_de ); +} + + + + +void audioFileProcessor::loadSettings( const QDomElement & _this ) +{ + setAudioFile( _this.attribute( "src" ) ); + setStartAndEndKnob( _this.attribute( "sframe" ).toFloat(), + _this.attribute( "eframe" ).toFloat() ); + m_reverseButton->setChecked( _this.attribute( "reversed" ).toInt() ); + m_loopButton->setChecked( _this.attribute( "looped" ).toInt() ); + m_ampKnob->setValue( _this.attribute( "amp" ).toFloat() ); +} + + + + +QString audioFileProcessor::nodeName( void ) const +{ + return( audiofileprocessor_plugin_descriptor.name ); +} + + + + +void audioFileProcessor::setParameter( const QString & _param, + const QString & _value ) +{ + if( _param == "audiofile" ) + { + setAudioFile( _value ); + } +} + + + + +Uint32 audioFileProcessor::getBeatLen( notePlayHandle * _n ) const +{ + const float freq_factor = BASE_FREQ / + ( getChannelTrack()->frequency( _n ) * + DEFAULT_SAMPLE_RATE / + mixer::inst()->sampleRate() ); + + return( static_cast( floorf( ( m_sampleBuffer.endFrame() - + m_sampleBuffer.startFrame() ) * + freq_factor ) ) ); +} + + + + +void audioFileProcessor::setAudioFile( const QString & _audio_file ) +{ + // is current channel-name equal to previous-filename?? + if( getChannelTrack()->name() == + QFileInfo( m_sampleBuffer.audioFile() ).fileName() || + m_sampleBuffer.audioFile() == "" ) + { + // then set it to new one + getChannelTrack()->setName( QFileInfo( _audio_file + ).fileName() ); + } + // else we don't touch the channel-name, because the user named it self + + m_sampleBuffer.setAudioFile( _audio_file ); + setStartAndEndKnob( 0.0f, 1.0f ); +} + + + + + +void audioFileProcessor::playNote( notePlayHandle * _n ) +{ + const Uint32 frames = mixer::inst()->framesPerAudioBuffer(); + sampleFrame * buf = bufferAllocator::alloc( frames ); + + // calculate frequency of note + const float note_freq = getChannelTrack()->frequency( _n ) / + ( mixer::inst()->sampleRate() / + DEFAULT_SAMPLE_RATE ); + + if( m_sampleBuffer.play( buf, _n->totalFramesPlayed(), + frames, note_freq, + m_loopButton->isChecked(), + &_n->m_pluginData ) == TRUE ) + { + getChannelTrack()->processAudioBuffer( buf, frames, _n ); + } + bufferAllocator::free( buf ); +} + + + + +void audioFileProcessor::deleteNotePluginData( notePlayHandle * _n ) +{ + if( _n->m_pluginData != NULL ) + { + m_sampleBuffer.deleteResamplingData( &_n->m_pluginData ); + } +} + + + + +void audioFileProcessor::paintEvent( QPaintEvent * ) +{ +#ifdef QT4 + QPainter p( this ); +#else + QPixmap pm( rect().size() ); + pm.fill( this, rect().topLeft() ); + + QPainter p( &pm, this ); +#endif + + p.drawPixmap( 0, 0, *s_artwork ); + + + QString file_name = ""; + Uint16 idx = m_sampleBuffer.audioFile().length(); + + p.setFont( pointSize<8>( p.font() ) ); + + QFontMetrics fm( font() ); + + // simple algorithm for creating a text from the filename that + // matches in the white rectangle +#ifdef QT4 + while( idx > 0 && + fm.size( Qt::TextSingleLine, file_name + "..." ).width() < 225 ) +#else + while( idx > 0 && + fm.size( Qt::SingleLine, file_name + "..." ).width() < 225 ) +#endif + { + file_name = m_sampleBuffer.audioFile()[--idx] + file_name; + } + + if( idx > 0 ) + { + file_name = "..." + file_name; + } + + p.setPen( QColor( 255, 255, 255 ) ); + p.drawText( 8, 84, file_name ); + + p.drawPixmap( 2, 172, m_graph ); + + + p.setPen( QColor( 0xFF, 0xAA, 0x00 ) ); + const QRect graph_rect( 4, 174, 241, 70 ); + const Uint32 frames = tMax( m_sampleBuffer.frames(), + static_cast( 1 ) ); + const Uint16 start_frame_x = m_sampleBuffer.startFrame() * + graph_rect.width() / frames; + const Uint16 end_frame_x = m_sampleBuffer.endFrame() * + ( graph_rect.width() - 1 ) / frames; + + p.drawLine( start_frame_x + graph_rect.x(), graph_rect.y(), + start_frame_x + graph_rect.x(), + graph_rect.height() + graph_rect.y() ); + p.drawLine( end_frame_x + graph_rect.x(), graph_rect.y(), + end_frame_x + graph_rect.x(), + graph_rect.height() + graph_rect.y() ); + +#ifndef QT4 + bitBlt( this, rect().topLeft(), &pm ); +#endif +} + + + + +void audioFileProcessor::sampleUpdated( void ) +{ + m_graph = QPixmap( 245, 75 ); + copyBlt( &m_graph, 0, 0, s_artwork, 2, 172, m_graph.width(), + m_graph.height() ); + QPainter p( &m_graph ); + m_sampleBuffer.drawWaves( p, QRect( 2, 2, m_graph.width() - 4, + m_graph.height() - 4 ), + m_drawMethod ); + update(); +} + + + + +void audioFileProcessor::reverseBtnToggled( bool _on ) +{ + m_sampleBuffer.setReversed( _on ); + songEditor::inst()->setModified(); +} + + + + +void audioFileProcessor::lineDrawBtnToggled( bool _on ) +{ + if( _on ) + { + m_drawMethod = sampleBuffer::LINE_CONNECT; + sampleUpdated(); + } +} + + + + +void audioFileProcessor::dotDrawBtnToggled( bool _on ) +{ + if( _on ) + { + m_drawMethod = sampleBuffer::DOTS; + sampleUpdated(); + } +} + + + + +void audioFileProcessor::ampKnobChanged( float _val ) +{ + m_sampleBuffer.setAmplification( _val/100.0f ); +} + + + + +void audioFileProcessor::setStartAndEndKnob( float _s, float _e ) +{ + // because the signal-handlers of valuechanges of start- and end-knob + // do range checking, depending on value of the other knob, we have to + // disconnect the signal-handlers, set then the values, connect again + // and then let the changes take effect... + m_startKnob->disconnect(); + m_endKnob->disconnect(); + m_startKnob->setValue( _s ); + m_endKnob->setValue( _e ); + connect( m_startKnob, SIGNAL( valueChanged( float ) ), this, + SLOT( startKnobChanged( float ) ) ); + connect( m_endKnob, SIGNAL( valueChanged( float ) ), this, + SLOT( endKnobChanged( float ) ) ); + m_startKnob->setValue( _s ); + m_endKnob->setValue( _e ); +} + + + + +void audioFileProcessor::startKnobChanged( float _new_value ) +{ + if( _new_value < m_endKnob->value() ) + { + m_sampleBuffer.setStartFrame( static_cast( _new_value * + m_sampleBuffer.frames() ) ); + } + else + { + m_startKnob->setValue( m_endKnob->value() - 0.01 ); + } + update(); +} + + + + +void audioFileProcessor::endKnobChanged( float _new_value ) +{ + if( _new_value > m_startKnob->value() ) + { + m_sampleBuffer.setEndFrame( static_cast( _new_value * + m_sampleBuffer.frames() ) - 1 ); + } + else + { + m_endKnob->setValue( m_startKnob->value() + 0.01 ); + } + update(); +} + + + + +void audioFileProcessor::openAudioFile( void ) +{ + QString af = m_sampleBuffer.openAudioFile(); + if( af != "" ) + { + setAudioFile( af ); + songEditor::inst()->setModified(); + } +} + + + + +extern "C" +{ + +// neccessary for getting instance out of shared lib +plugin * lmms_plugin_main( void * _data ) +{ + return( new audioFileProcessor( + static_cast( _data ) ) ); +} + + +} + + + +#undef isChecked +#undef isOn + +#include "audio_file_processor.moc" + diff --git a/plugins/audio_file_processor/audio_file_processor.h b/plugins/audio_file_processor/audio_file_processor.h new file mode 100644 index 000000000..b236d7f2b --- /dev/null +++ b/plugins/audio_file_processor/audio_file_processor.h @@ -0,0 +1,116 @@ +/* + * audio_file_processor.h - declaration of class audioFileProcessor + * (instrument-plugin for using audio-files) + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _AUDIO_FILE_PROCESSOR_H +#define _AUDIO_FILE_PROCESSOR_H + +#include "qt3support.h" + +#ifdef QT4 + +#include + +#else + +#include + +#endif + +#include "instrument.h" +#include "sample_buffer.h" +#include "spc_bg_hndl_widget.h" + + +class knob; +class pixmapButton; + + +class audioFileProcessor : public instrument, public specialBgHandlingWidget +{ + Q_OBJECT +public: + audioFileProcessor( channelTrack * _channel_track ); + virtual ~audioFileProcessor(); + + virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); + + virtual void FASTCALL saveSettings( QDomDocument & _doc, + QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + + virtual void FASTCALL setParameter( const QString & _param, + const QString & _value ); + + virtual QString nodeName( void ) const; + + virtual Uint32 FASTCALL getBeatLen( notePlayHandle * _n ) const; + + +public slots: + void setAudioFile( const QString & _audio_file ); + + +protected slots: + void openAudioFile( void ); + void reverseBtnToggled( bool _on ); + void ampKnobChanged( float _new_value ); + void startKnobChanged( float _new_value ); + void endKnobChanged( float _new_value ); + void lineDrawBtnToggled( bool _on ); + void dotDrawBtnToggled( bool _on ); + void sampleUpdated( void ); + + +protected: + void paintEvent( QPaintEvent * ); + + +private: + static QPixmap * s_artwork; + + + sampleBuffer m_sampleBuffer; + + sampleBuffer::drawMethods m_drawMethod; + + QPixmap m_graph; + knob * m_ampKnob; + knob * m_startKnob; + knob * m_endKnob; + pixmapButton * m_openAudioFileButton; + pixmapButton * m_viewLinesPB; + pixmapButton * m_viewDotsPB; + pixmapButton * m_reverseButton; + pixmapButton * m_loopButton; + + + void updateSample( void ); + void FASTCALL setStartAndEndKnob( float _s, float _e ); + +} ; + + +#endif diff --git a/plugins/audio_file_processor/logo.png b/plugins/audio_file_processor/logo.png new file mode 100644 index 000000000..ec8b2569c Binary files /dev/null and b/plugins/audio_file_processor/logo.png differ diff --git a/plugins/audio_file_processor/loop_off.png b/plugins/audio_file_processor/loop_off.png new file mode 100644 index 000000000..8b7ddd39e Binary files /dev/null and b/plugins/audio_file_processor/loop_off.png differ diff --git a/plugins/audio_file_processor/loop_on.png b/plugins/audio_file_processor/loop_on.png new file mode 100644 index 000000000..bdb0c47f2 Binary files /dev/null and b/plugins/audio_file_processor/loop_on.png differ diff --git a/plugins/audio_file_processor/reverse_off.png b/plugins/audio_file_processor/reverse_off.png new file mode 100644 index 000000000..be0f502ca Binary files /dev/null and b/plugins/audio_file_processor/reverse_off.png differ diff --git a/plugins/audio_file_processor/reverse_on.png b/plugins/audio_file_processor/reverse_on.png new file mode 100644 index 000000000..42774aded Binary files /dev/null and b/plugins/audio_file_processor/reverse_on.png differ diff --git a/plugins/plucked_string_synth/Makefile.am b/plugins/plucked_string_synth/Makefile.am new file mode 100644 index 000000000..40e103b7b --- /dev/null +++ b/plugins/plucked_string_synth/Makefile.am @@ -0,0 +1,33 @@ +AUTOMAKE_OPTIONS = foreign 1.4 + + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I. + + +AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="pluckedstringsynth" + + +%.moc: ./%.h + $(MOC) -o $@ $< + + +MOC_FILES = ./plucked_string_synth.moc + +BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h +EMBEDDED_RESOURCES = $(wildcard *png) + +./embedded_resources.h: $(EMBEDDED_RESOURCES) + $(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@ + +EXTRA_DIST = $(EMBEDDED_RESOURCES) + + +CLEANFILES = $(MOC_FILES) ./embedded_resources.h + + + +pkglib_LTLIBRARIES= libpluckedstringsynth.la + +libpluckedstringsynth_la_SOURCES = plucked_string_synth.cpp plucked_string_synth.h + +$(libpluckedstringsynth_la_SOURCES): ./embedded_resources.h diff --git a/plugins/plucked_string_synth/artwork.png b/plugins/plucked_string_synth/artwork.png new file mode 100644 index 000000000..d972d0744 Binary files /dev/null and b/plugins/plucked_string_synth/artwork.png differ diff --git a/plugins/plucked_string_synth/logo.png b/plugins/plucked_string_synth/logo.png new file mode 100644 index 000000000..2582b463c Binary files /dev/null and b/plugins/plucked_string_synth/logo.png differ diff --git a/plugins/plucked_string_synth/plucked_string_synth.cpp b/plugins/plucked_string_synth/plucked_string_synth.cpp new file mode 100644 index 000000000..1ebfbc701 --- /dev/null +++ b/plugins/plucked_string_synth/plucked_string_synth.cpp @@ -0,0 +1,274 @@ +/* + * plucked_string_synth.cpp - instrument which uses the Karplus-Strong-algorithm + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include + +#else + +#include +#include + +#endif + + +#include "plucked_string_synth.h" +#include "channel_track.h" +#include "note_play_handle.h" +#include "templates.h" +#include "buffer_allocator.h" +#include "knob.h" + +#include "embed.cpp" + + +extern "C" +{ + +plugin::descriptor pluckedstringsynth_plugin_descriptor = +{ + STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ), + "PluckedStringSynth", + QT_TRANSLATE_NOOP( "plugin", + "cheap synthesis of guitar/harp-like sounds" ), + "Tobias Doerffel ", + 0x0100, + plugin::INSTRUMENT, + PLUGIN_NAME::findEmbeddedData( "logo.png" ) +} ; + +} + + +// TODO: make this synth stereo for better better spacial (room) feeling and +// add distortion + +pluckedStringSynth::pluckedStringSynth( channelTrack * _channel_track ) : + instrument( _channel_track, + pluckedstringsynth_plugin_descriptor.public_name ) +{ + m_pickKnob = new knob( knobDark_28, this, tr( "Pick position" ) ); + m_pickKnob->setRange( 0.0f, 0.5f, 0.005f ); + m_pickKnob->setValue( 0.0f, TRUE ); + m_pickKnob->move( 86, 134 ); + m_pickKnob->setHintText( tr( "Pick position:" ) + " ", "" ); + + m_pickupKnob = new knob( knobDark_28, this, tr( "Pickup position" ) ); + m_pickupKnob->setRange( 0.0f, 0.5f, 0.005f ); + m_pickupKnob->setValue( 0.05f, TRUE ); + m_pickupKnob->move( 138, 134 ); + m_pickupKnob->setHintText( tr( "Pickup position:" ) + " ", "" ); +#ifdef QT4 + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( + "artwork" ) ); + setPalette( pal ); +#else + setErasePixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) ); +#endif +} + + + + +pluckedStringSynth::~pluckedStringSynth() +{ +} + + + + +void pluckedStringSynth::saveSettings( QDomDocument & _doc, + QDomElement & _parent ) +{ + QDomElement pss_de = _doc.createElement( nodeName() ); + pss_de.setAttribute( "pick", QString::number( m_pickKnob->value() ) ); + pss_de.setAttribute( "pickup", QString::number( + m_pickupKnob->value() ) ); + _parent.appendChild( pss_de ); +} + + + + +void pluckedStringSynth::loadSettings( const QDomElement & _this ) +{ + m_pickKnob->setValue( _this.attribute( "pick" ).toFloat() ); + m_pickupKnob->setValue( _this.attribute( "pickup" ).toFloat() ); +} + + + + +QString pluckedStringSynth::nodeName( void ) const +{ + return( pluckedstringsynth_plugin_descriptor.name ); +} + + + + +void pluckedStringSynth::playNote( notePlayHandle * _n ) +{ + if ( _n->totalFramesPlayed() == 0 ) + { + float freq = getChannelTrack()->frequency( _n ); + _n->m_pluginData = new pluckSynth( freq, m_pickKnob->value(), + m_pickupKnob->value() ); + } + + const Uint32 frames = mixer::inst()->framesPerAudioBuffer(); + sampleFrame * buf = bufferAllocator::alloc( frames ); + + pluckSynth * ps = static_cast( _n->m_pluginData ); + for( Uint32 frame = 0; frame < frames; ++frame ) + { + const sampleType cur = ps->nextStringSample(); + for( Uint8 chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl ) + { + buf[frame][chnl] = cur; + } + } + + getChannelTrack()->processAudioBuffer( buf, frames, _n ); + + bufferAllocator::free( buf ); +} + + + + +void pluckedStringSynth::deleteNotePluginData( notePlayHandle * _n ) +{ + delete static_cast( _n->m_pluginData ); +} + + + + + +pluckSynth::delayLine * FASTCALL pluckSynth::initDelayLine( int _len ) +{ + delayLine * dl = new pluckSynth::delayLine[_len]; + dl->length = _len; + if( _len > 0 ) + { + dl->data = new sampleType[_len]; + } + else + { + dl->data = NULL; + } + + dl->pointer = dl->data; + dl->end = dl->data + _len - 1; + + return( dl ); +} + + + + +void FASTCALL pluckSynth::freeDelayLine( delayLine * _dl ) +{ + if( _dl && _dl->data ) + { + delete[] _dl->data; + } + + _dl->data = NULL; + delete[] _dl; +} + + + + +pluckSynth::pluckSynth( float _pitch, float _pick, float _pickup ) +{ + const float AMP = 1.5f; + int rail_length = static_cast( mixer::inst()->sampleRate() / 2 / + _pitch ) + 1; + // Round pick position to nearest spatial sample. + // A pick position at x = 0 is not allowed. + int pick_sample = static_cast( tMax( rail_length * _pick, + 1.0f ) ); + float initial_shape[rail_length]; + + m_upperRail = pluckSynth::initDelayLine( rail_length ); + m_lowerRail = pluckSynth::initDelayLine( rail_length ); + +//#define METALLIC_PLUCK +#ifdef METALLIC_PLUCK + for ( int i = 0; i < rail_length; i++ ) + { + initial_shape[i] = rand() * AMP / RAND_MAX; + } + + initial_shape[pick_sample] = 0.5; + initial_shape[pick_sample+1] = 0.5; + +#else + float upslope = AMP / pick_sample; + const float downslope = AMP / ( rail_length - pick_sample - 1 ); + + for( int i = 0; i < pick_sample; i++ ) + { + initial_shape[i] = upslope * i; + } + + for( int i = pick_sample; i < rail_length; i++ ) + { + initial_shape[i] = downslope * ( rail_length - 1 - i ); + } +#endif + + // Initial conditions for the ideal plucked string. + // "Past history" is measured backward from the end of the array. + pluckSynth::setDelayLine( m_lowerRail, initial_shape, 0.5f ); + pluckSynth::setDelayLine( m_upperRail, initial_shape, 0.5f ); + + m_pickupLoc = static_cast( _pickup * rail_length ); +} + + + + +extern "C" +{ + +// neccessary for getting instance out of shared lib +plugin * lmms_plugin_main( void * _data ) +{ + return( new pluckedStringSynth( + static_cast( _data ) ) ); +} + + +} + + diff --git a/plugins/plucked_string_synth/plucked_string_synth.h b/plugins/plucked_string_synth/plucked_string_synth.h new file mode 100644 index 000000000..b066f8903 --- /dev/null +++ b/plugins/plucked_string_synth/plucked_string_synth.h @@ -0,0 +1,216 @@ +/* + * plucked_string_sytn.h - declaration of class pluckedStringSynth which + * is a synth for plucked string-sounds + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _PLUCKED_STRING_SYNTH_H +#define _PLUCKED_STRING_SYNTH_H + +#include "instrument.h" + + +class knob; +class notePlayHandle; + + +// the actual synth +class pluckSynth +{ +public: + pluckSynth( float _pitch, float _pick, float _pickup ); + + inline ~pluckSynth( void ) + { + pluckSynth::freeDelayLine( m_upperRail ); + pluckSynth::freeDelayLine( m_lowerRail ); + } + + inline sampleType nextStringSample( void ) + { + // Output at pickup position + sampleType outsamp = rgDlAccess( m_upperRail, m_pickupLoc ); + outsamp += lgDlAccess( m_lowerRail, m_pickupLoc ); + + // Sample traveling into "bridge" + sampleType ym0 = lgDlAccess( m_lowerRail, 1 ); + // Sample to "nut" + sampleType ypM = rgDlAccess( m_upperRail, + m_upperRail->length - 2 ); + + // String state update + + // Decrement pointer and then update + rgDlUpdate( m_upperRail, -bridgeReflection( ym0 ) ); + // Update and then increment pointer + lgDlUpdate( m_lowerRail, -ypM ); + + return( outsamp ); + } + + +private: + struct delayLine + { + sampleType * data; + int length; + sampleType * pointer; + sampleType * end; + } ; + + delayLine * m_upperRail; + delayLine * m_lowerRail; + int m_pickupLoc; + + static delayLine * FASTCALL initDelayLine( int _len ); + static void FASTCALL freeDelayLine( delayLine * _dl ); + static inline void setDelayLine( delayLine * _dl, float * _values, + float _scale ) + { + for( int i = 0; i < _dl->length; ++i ) + { + _dl->data[i] = _scale * _values[i]; + } + } + + /* lgDlUpdate(dl, insamp); + * Places "nut-reflected" sample from upper delay-line into + * current lower delay-line pointer position (which represents + * x = 0 position). The pointer is then incremented (i.e. the + * wave travels one sample to the left), turning the previous + * position into an "effective" x = L position for the next + * iteration. */ + static inline void lgDlUpdate( delayLine * _dl, sampleType _insamp ) + { + register sampleType * ptr = _dl->pointer; + *ptr = _insamp; + ++ptr; + if( ptr > _dl->end ) + { + ptr = _dl->data; + } + _dl->pointer = ptr; + } + + /* rgDlUpdate(dl, insamp); + * Decrements current upper delay-line pointer position (i.e. + * the wave travels one sample to the right), moving it to the + * "effective" x = 0 position for the next iteration. The + * "bridge-reflected" sample from lower delay-line is then placed + * into this position. */ + static inline void rgDlUpdate( delayLine * _dl, sampleType _insamp ) + { + register sampleType * ptr = _dl->pointer; + --ptr; + if( ptr < _dl->data ) + { + ptr = _dl->end; + } + *ptr = _insamp; + _dl->pointer = ptr; + } + + /* dlAccess(dl, position); + * Returns sample "position" samples into delay-line's past. + * Position "0" points to the most recently inserted sample. */ + static inline sampleType dlAccess( delayLine * _dl, int _position ) + { + sampleType * outpos = _dl->pointer + _position; + while( outpos < _dl->data ) + { + outpos += _dl->length; + } + while( outpos > _dl->end ) + { + outpos -= _dl->length; + } + return( *outpos ); + } + + /* + * Right-going delay line: + * -->---->---->--- + * x=0 + * (pointer) + * Left-going delay line: + * --<----<----<--- + * x=0 + * (pointer) + */ + + /* rgDlAccess(dl, position); + * Returns spatial sample at position "position", where position zero + * is equal to the current upper delay-line pointer position (x = 0). + * In a right-going delay-line, position increases to the right, and + * delay increases to the right => left = past and right = future. */ + static inline sampleType rgDlAccess( delayLine * _dl, int _position ) + { + return( dlAccess( _dl, _position ) ); + } + + /* lgDlAccess(dl, position); + * Returns spatial sample at position "position", where position zero + * is equal to the current lower delay-line pointer position (x = 0). + * In a left-going delay-line, position increases to the right, and + * delay DEcreases to the right => left = future and right = past. */ + static inline sampleType lgDlAccess( delayLine * _dl, int _position ) + { + return( dlAccess( _dl, _position ) ); + } + + static inline sampleType bridgeReflection( sampleType _insamp ) + { + static sampleType state = 0.0f; // filter memory + // Implement a one-pole lowpass with feedback coefficient = 0.5 + return( state = state*0.5f + _insamp*0.5f ); + } + +} ; + + + + +class pluckedStringSynth : public instrument +{ +public: + pluckedStringSynth(channelTrack * _channel_track ); + virtual ~pluckedStringSynth(); + + virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); + + + virtual void FASTCALL saveSettings( QDomDocument & _doc, + QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + + virtual QString nodeName( void ) const; + + +private: + knob * m_pickKnob; + knob * m_pickupKnob; + +} ; + + +#endif diff --git a/plugins/triple_oscillator/Makefile.am b/plugins/triple_oscillator/Makefile.am new file mode 100644 index 000000000..fd40793ad --- /dev/null +++ b/plugins/triple_oscillator/Makefile.am @@ -0,0 +1,33 @@ +AUTOMAKE_OPTIONS = foreign 1.4 + + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I. + + +AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="tripleoscillator" + + +%.moc: ./%.h + $(MOC) -o $@ $< + + +MOC_FILES = ./triple_oscillator.moc + +BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h +EMBEDDED_RESOURCES = $(wildcard *png) + +./embedded_resources.h: $(EMBEDDED_RESOURCES) + $(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@ + +EXTRA_DIST = $(EMBEDDED_RESOURCES) + + +CLEANFILES = $(MOC_FILES) ./embedded_resources.h + + + +pkglib_LTLIBRARIES= libtripleoscillator.la + +libtripleoscillator_la_SOURCES = triple_oscillator.cpp triple_oscillator.h + +$(libtripleoscillator_la_SOURCES): ./embedded_resources.h diff --git a/plugins/triple_oscillator/am_active.png b/plugins/triple_oscillator/am_active.png new file mode 100644 index 000000000..88ea2abc5 Binary files /dev/null and b/plugins/triple_oscillator/am_active.png differ diff --git a/plugins/triple_oscillator/am_inactive.png b/plugins/triple_oscillator/am_inactive.png new file mode 100644 index 000000000..dee2a872f Binary files /dev/null and b/plugins/triple_oscillator/am_inactive.png differ diff --git a/plugins/triple_oscillator/artwork.png b/plugins/triple_oscillator/artwork.png new file mode 100644 index 000000000..13fbfe9f1 Binary files /dev/null and b/plugins/triple_oscillator/artwork.png differ diff --git a/plugins/triple_oscillator/btn_mask.png b/plugins/triple_oscillator/btn_mask.png new file mode 100644 index 000000000..bd257ea55 Binary files /dev/null and b/plugins/triple_oscillator/btn_mask.png differ diff --git a/plugins/triple_oscillator/fm_active.png b/plugins/triple_oscillator/fm_active.png new file mode 100644 index 000000000..ea92fbfd8 Binary files /dev/null and b/plugins/triple_oscillator/fm_active.png differ diff --git a/plugins/triple_oscillator/fm_inactive.png b/plugins/triple_oscillator/fm_inactive.png new file mode 100644 index 000000000..0ed75fd97 Binary files /dev/null and b/plugins/triple_oscillator/fm_inactive.png differ diff --git a/plugins/triple_oscillator/logo.png b/plugins/triple_oscillator/logo.png new file mode 100644 index 000000000..0b1d27664 Binary files /dev/null and b/plugins/triple_oscillator/logo.png differ diff --git a/plugins/triple_oscillator/mix_active.png b/plugins/triple_oscillator/mix_active.png new file mode 100644 index 000000000..33d93e911 Binary files /dev/null and b/plugins/triple_oscillator/mix_active.png differ diff --git a/plugins/triple_oscillator/mix_inactive.png b/plugins/triple_oscillator/mix_inactive.png new file mode 100644 index 000000000..6f085b526 Binary files /dev/null and b/plugins/triple_oscillator/mix_inactive.png differ diff --git a/plugins/triple_oscillator/sync_active.png b/plugins/triple_oscillator/sync_active.png new file mode 100644 index 000000000..652661ea6 Binary files /dev/null and b/plugins/triple_oscillator/sync_active.png differ diff --git a/plugins/triple_oscillator/sync_inactive.png b/plugins/triple_oscillator/sync_inactive.png new file mode 100644 index 000000000..7eb324ab5 Binary files /dev/null and b/plugins/triple_oscillator/sync_inactive.png differ diff --git a/plugins/triple_oscillator/triple_oscillator.cpp b/plugins/triple_oscillator/triple_oscillator.cpp new file mode 100644 index 000000000..4f13bb115 --- /dev/null +++ b/plugins/triple_oscillator/triple_oscillator.cpp @@ -0,0 +1,1222 @@ +/* + * triple_oscillator.cpp - powerful instrument with three oscillators + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +#include +#include + +#else + +#include +#include +#include +#include + +#define setChecked setOn + +#endif + + +#include "triple_oscillator.h" +#include "song_editor.h" +#include "channel_track.h" +#include "note_play_handle.h" +#include "knob.h" +#include "pixmap_button.h" +#include "buffer_allocator.h" +#include "debug.h" +#include "tooltip.h" + +#include "embed.cpp" + + +extern "C" +{ + +plugin::descriptor tripleoscillator_plugin_descriptor = +{ + STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ), + "TripleOscillator", + QT_TRANSLATE_NOOP( "plugin", + "three powerful oscillators you can modulate " + "in several ways" ), + "Tobias Doerffel ", + 0x0100, + plugin::INSTRUMENT, + PLUGIN_NAME::findEmbeddedData( "logo.png" ) +} ; + +} + + +tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : + instrument( _channel_track, + tripleoscillator_plugin_descriptor.public_name ), + m_modulationAlgo1( oscillator::MIX ), + m_modulationAlgo2( oscillator::MIX ) +{ +#ifdef QT4 + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) ); + setPalette( pal ); +#else + setErasePixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) ); +#endif + + m_fm1OscBtn = new pixmapButton( this ); + m_fm1OscBtn->move( 80, 50 ); + m_fm1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "fm_active" ) ); + m_fm1OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "fm_inactive" ) ); + m_fm1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + connect( m_fm1OscBtn, SIGNAL( toggled( bool ) ), this, + SLOT( fm1BtnToggled( bool ) ) ); + toolTip::add( m_fm1OscBtn, tr( "use frequency modulation for " + "modulating oscillator 2 with " + "oscillator 1" ) ); + + m_am1OscBtn = new pixmapButton( this ); + m_am1OscBtn->move( 120, 50 ); + m_am1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "am_active" ) ); + m_am1OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "am_inactive" ) ); + m_am1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + connect( m_am1OscBtn, SIGNAL( toggled( bool ) ), this, + SLOT( am1BtnToggled( bool ) ) ); + toolTip::add( m_am1OscBtn, tr( "use amplitude modulation for " + "modulating oscillator 2 with " + "oscillator 1" ) ); + + m_mix1OscBtn = new pixmapButton( this ); + m_mix1OscBtn->move( 160, 50 ); + m_mix1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "mix_active" ) ); + m_mix1OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "mix_inactive" ) ); + m_mix1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + connect( m_mix1OscBtn, SIGNAL( toggled( bool ) ), this, + SLOT( mix1BtnToggled( bool ) ) ); + toolTip::add( m_mix1OscBtn, tr( "mix output of oscillator 1 & 2" ) ); + + m_sync1OscBtn = new pixmapButton( this ); + m_sync1OscBtn->move( 200, 50 ); + m_sync1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "sync_active" ) ); + m_sync1OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "sync_inactive" ) ); + m_sync1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + connect( m_sync1OscBtn, SIGNAL( toggled( bool ) ), this, SLOT( + sync1BtnToggled( bool ) ) ); + toolTip::add( m_sync1OscBtn, tr( "synchronize oscillator 1 with " + "oscillator 2" ) ); + + if( m_modulationAlgo1 == oscillator::FREQ_MODULATION ) + { + m_fm1OscBtn->setChecked( TRUE ); + } + else if( m_modulationAlgo1 == oscillator::AMP_MODULATION ) + { + m_am1OscBtn->setChecked( TRUE ); + } + else if( m_modulationAlgo1 == oscillator::MIX ) + { + m_mix1OscBtn->setChecked( TRUE ); + } + else if( m_modulationAlgo1 == oscillator::SYNC ) + { + m_sync1OscBtn->setChecked( TRUE ); + } + + QButtonGroup * modulation_algo_group1 = new QButtonGroup( this ); + modulation_algo_group1->addButton( m_fm1OscBtn ); + modulation_algo_group1->addButton( m_am1OscBtn ); + modulation_algo_group1->addButton( m_mix1OscBtn ); + modulation_algo_group1->addButton( m_sync1OscBtn ); + modulation_algo_group1->setExclusive( TRUE ); +#ifndef QT4 + modulation_algo_group1->hide(); +#endif + + m_fm2OscBtn = new pixmapButton( this ); + m_fm2OscBtn->move( 80, 70 ); + m_fm2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "fm_active" ) ); + m_fm2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "fm_inactive" ) ); + m_fm2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + connect( m_fm2OscBtn, SIGNAL( toggled( bool ) ), this, SLOT( + fm2BtnToggled( bool ) ) ); + toolTip::add( m_fm2OscBtn, tr( "use frequency modulation for " + "modulating oscillator 3 with " + "oscillator 2" ) ); + + m_am2OscBtn = new pixmapButton( this ); + m_am2OscBtn->move( 120, 70 ); + m_am2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "am_active" ) ); + m_am2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap("am_inactive" ) ); + m_am2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + connect( m_am2OscBtn, SIGNAL( toggled( bool ) ), this, + SLOT( am2BtnToggled( bool ) ) ); + toolTip::add( m_am2OscBtn, tr( "use amplitude modulation for " + "modulating oscillator 3 with " + "oscillator 2" ) ); + + m_mix2OscBtn = new pixmapButton( this ); + m_mix2OscBtn->move( 160, 70 ); + m_mix2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "mix_active" ) ); + m_mix2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "mix_inactive" ) ); + m_mix2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + connect( m_mix2OscBtn, SIGNAL( toggled( bool ) ), this, + SLOT( mix2BtnToggled( bool ) ) ); + toolTip::add( m_mix2OscBtn, tr("mix output of oscillator 2 & 3" ) ); + + m_sync2OscBtn = new pixmapButton( this ); + m_sync2OscBtn->move( 200, 70 ); + m_sync2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "sync_active" ) ); + m_sync2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "sync_inactive" ) ); + m_sync2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + connect( m_sync2OscBtn, SIGNAL( toggled( bool ) ), this, + SLOT( sync2BtnToggled( bool ) ) ); + toolTip::add( m_sync2OscBtn, tr( "synchronize oscillator 2 with " + "oscillator 3" ) ); + + if( m_modulationAlgo2 == oscillator::FREQ_MODULATION ) + { + m_fm2OscBtn->setChecked( TRUE ); + } + else if( m_modulationAlgo2 == oscillator::AMP_MODULATION ) + { + m_am2OscBtn->setChecked( TRUE ); + } + else if( m_modulationAlgo2 == oscillator::MIX ) + { + m_mix2OscBtn->setChecked( TRUE ); + } + else if( m_modulationAlgo2 == oscillator::SYNC ) + { + m_sync2OscBtn->setChecked( TRUE ); + } + + QButtonGroup * modulation_algo_group2 = new QButtonGroup( this ); + modulation_algo_group2->addButton( m_fm2OscBtn ); + modulation_algo_group2->addButton( m_am2OscBtn ); + modulation_algo_group2->addButton( m_mix2OscBtn ); + modulation_algo_group2->addButton( m_sync2OscBtn ); + modulation_algo_group2->setExclusive( TRUE ); +#ifndef QT4 + modulation_algo_group2->hide(); +#endif + + + for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) + { + // reset current m_osc-structure + m_osc[i].waveShape = oscillator::SIN_WAVE; + + // setup volume-knob + m_osc[i].volKnob = new knob( knobSmall_17, this, tr( + "Osc %1 volume" ).arg( i+1 ) ); + m_osc[i].volKnob->move( 6, 104+i*50 ); + m_osc[i].volKnob->setRange( MIN_VOLUME, MAX_VOLUME, 1.0f ); + m_osc[i].volKnob->setValue( DEFAULT_VOLUME, TRUE ); + m_osc[i].volKnob->setHintText( tr( "Osc %1 volume:" ).arg( + i+1 ) + " ", "%" ); +#ifdef QT4 + m_osc[i].volKnob->setWhatsThis( +#else + QWhatsThis::add( m_osc[i].volKnob, +#endif + tr( "With this knob you can set the volume of " + "oscillator %1. When setting a value of 0 the " + "oscillator is turned off. Otherwise you can " + "hear the oscillator as loud as you set it " + "here.").arg( i+1 ) ); + + // setup panning-knob + m_osc[i].panKnob = new knob( knobSmall_17, this, + tr( "Osc %1 panning" ).arg( i + 1 ) ); + m_osc[i].panKnob->move( 33, 104+i*50 ); + m_osc[i].panKnob->setRange( PANNING_LEFT, PANNING_RIGHT, 1.0f ); + m_osc[i].panKnob->setValue( DEFAULT_PANNING, TRUE ); + m_osc[i].panKnob->setHintText( tr("Osc %1 panning:").arg( i+1 ) + + " ", "" ); +#ifdef QT4 + m_osc[i].panKnob->setWhatsThis( +#else + QWhatsThis::add( m_osc[i].panKnob, +#endif + tr( "With this knob you can set the panning of the " + "oscillator %1. A value of -100 means 100% " + "left and a value of 100 moves oscillator-" + "output right.").arg( i+1 ) ); + + // setup coarse-knob + m_osc[i].coarseKnob = new knob( knobSmall_17, this, + tr("Osc %1 coarse detuning").arg( i + 1 ) ); + m_osc[i].coarseKnob->move( 66, 104 + i * 50 ); + m_osc[i].coarseKnob->setRange( -2 * NOTES_PER_OCTAVE, + 2 * NOTES_PER_OCTAVE, 1.0f ); + m_osc[i].coarseKnob->setValue( 0.0f, TRUE ); + m_osc[i].coarseKnob->setHintText( tr( "Osc %1 coarse detuning:" + ).arg( i + 1 ) + " ", + " " + tr( "semitones" ) ); +#ifdef QT4 + m_osc[i].coarseKnob->setWhatsThis( +#else + QWhatsThis::add( m_osc[i].coarseKnob, +#endif + tr( "With this knob you can set the coarse detuning of " + "oscillator %1. You can detune the oscillator " + "12 semitones (1 octave) up and down. This is " + "useful for creating sounds with a chord." ). + arg( i + 1 ) ); + + // setup knob for left fine-detuning + m_osc[i].fineLKnob = new knob( knobSmall_17, this, + tr( "Osc %1 fine detuning left" ).arg( i+1 ) ); + m_osc[i].fineLKnob->move( 90, 104 + i * 50 ); + m_osc[i].fineLKnob->setRange( -100.0f, 100.0f, 1.0f ); + m_osc[i].fineLKnob->setValue( 0.0f, TRUE ); + m_osc[i].fineLKnob->setHintText( tr( "Osc %1 fine detuning " + "left:" ).arg( i + 1 ) + + " ", " " + + tr( "cents" ) ); +#ifdef QT4 + m_osc[i].fineLKnob->setWhatsThis( +#else + QWhatsThis::add( m_osc[i].fineLKnob, +#endif + tr( "With this knob you can set the fine detuning of " + "oscillator %1 for the left channel. The fine-" + "detuning is ranged between -100 cents and " + "+100 cents. This is useful for creating " + "\"fat\" sounds." ).arg( i + 1 ) ); + + // setup knob for right fine-detuning + m_osc[i].fineRKnob = new knob( knobSmall_17, this, + tr( "Osc %1 fine detuning right" + ).arg( i + 1 ) ); + m_osc[i].fineRKnob->move( 110, 104 + i * 50 ); + m_osc[i].fineRKnob->setRange( -100.0f, 100.0f, 1.0f ); + m_osc[i].fineRKnob->setValue( 0.0f, TRUE ); + m_osc[i].fineRKnob->setHintText( tr( "Osc %1 fine detuning " + "right:").arg( i + 1 ) + + " ", " " + tr( "cents" ) ); +#ifdef QT4 + m_osc[i].fineRKnob->setWhatsThis( +#else + QWhatsThis::add( m_osc[i].fineRKnob, +#endif + tr( "With this knob you can set the fine detuning of " + "oscillator %1 for the right channel. The " + "fine-detuning is ranged between -100 cents " + "and +100 cents. This is useful for creating " + "\"fat\" sounds." ).arg( i+1 ) ); + + // setup phase-offset-knob + m_osc[i].phaseOffsetKnob = new knob( knobSmall_17, this, + tr( "Osc %1 phase-" + "offset" ).arg( i+1 ) ); + m_osc[i].phaseOffsetKnob->move( 142, 104 + i * 50 ); + m_osc[i].phaseOffsetKnob->setRange( 0.0f, 360.0f, 1.0f ); + m_osc[i].phaseOffsetKnob->setValue( 0.0f, TRUE ); + m_osc[i].phaseOffsetKnob->setHintText( tr( "Osc %1 phase-" + "offset:" ). + arg( i + 1 ) + + " ", " " + tr( "degrees" ) ); +#ifdef QT4 + m_osc[i].phaseOffsetKnob->setWhatsThis( +#else + QWhatsThis::add( m_osc[i].phaseOffsetKnob, +#endif + tr( "With this knob you can set the phase-offset of " + "oscillator %1. That means you can move the " + "point within an oscillation where the " + "oscillator begins to oscillate. For example " + "if you have a sine-wave and have a phase-" + "offset of 180 degrees the wave will first go " + "down. It's the same with a square-wave." + ).arg( i+1 ) ); + + // setup stereo-phase-detuning-knob + m_osc[i].stereoPhaseDetuningKnob = new knob( knobSmall_17, this, + tr( "Osc %1 stereo phase-" + "detuning" ).arg( i+1 ) + ); + m_osc[i].stereoPhaseDetuningKnob->move( 166, 104 + i * 50 ); + m_osc[i].stereoPhaseDetuningKnob->setRange( 0.0f, 360.0f, + 1.0f ); + m_osc[i].stereoPhaseDetuningKnob->setValue( 0.0f, TRUE ); + m_osc[i].stereoPhaseDetuningKnob->setHintText( tr("Osc %1 " + "stereo phase-" + "detuning:" ). + arg( i + 1 ) + + " ", " " + + tr( "degrees" ) ); +#ifdef QT4 + m_osc[i].stereoPhaseDetuningKnob->setWhatsThis( +#else + QWhatsThis::add( m_osc[i].stereoPhaseDetuningKnob, +#endif + tr( "With this knob you can set the stereo phase-" + "detuning of oscillator %1. The stereo phase-" + "detuning specifies the size of the difference " + "between the phase-offset of left and right " + "channel. This is very good for creating wide " + "stereo-sounds." ).arg( i+1 ) ); + + m_osc[i].sinWaveBtn = new pixmapButton( this ); + m_osc[i].sinWaveBtn->move( 188, 105 + i * 50 ); + m_osc[i].sinWaveBtn->setActiveGraphic( embed::getIconPixmap( + "sin_wave_active" ) ); + m_osc[i].sinWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "sin_wave_inactive" ) ); + m_osc[i].sinWaveBtn->setChecked( TRUE ); + toolTip::add( m_osc[i].sinWaveBtn, + tr( "Click here if you want a sine-wave for " + "current oscillator." ) ); + + m_osc[i].triangleWaveBtn = new pixmapButton( this ); + m_osc[i].triangleWaveBtn->move( 203, 105 + i * 50 ); + m_osc[i].triangleWaveBtn->setActiveGraphic( + embed::getIconPixmap( "triangle_wave_active" ) ); + m_osc[i].triangleWaveBtn->setInactiveGraphic( + embed::getIconPixmap( "triangle_wave_inactive" ) ); + toolTip::add( m_osc[i].triangleWaveBtn, + tr( "Click here if you want a triangle-wave " + "for current oscillator." ) ); + + m_osc[i].sawWaveBtn = new pixmapButton( this ); + m_osc[i].sawWaveBtn->move( 218, 105 + i * 50 ); + m_osc[i].sawWaveBtn->setActiveGraphic( embed::getIconPixmap( + "saw_wave_active" ) ); + m_osc[i].sawWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "saw_wave_inactive" ) ); + toolTip::add( m_osc[i].sawWaveBtn, + tr( "Click here if you want a saw-wave for " + "current oscillator." ) ); + + m_osc[i].sqrWaveBtn = new pixmapButton( this ); + m_osc[i].sqrWaveBtn->move( 233, 105 + i * 50 ); + m_osc[i].sqrWaveBtn->setActiveGraphic( embed::getIconPixmap( + "square_wave_active" ) ); + m_osc[i].sqrWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "square_wave_inactive" ) ); + toolTip::add( m_osc[i].sqrWaveBtn, + tr( "Click here if you want a square-wave for " + "current oscillator." ) ); + + m_osc[i].moogSawWaveBtn = new pixmapButton( this ); + m_osc[i].moogSawWaveBtn->move( 188, 120+i*50 ); + m_osc[i].moogSawWaveBtn->setActiveGraphic( + embed::getIconPixmap( "moog_saw_wave_active" ) ); + m_osc[i].moogSawWaveBtn->setInactiveGraphic( + embed::getIconPixmap( "moog_saw_wave_inactive" ) ); + toolTip::add( m_osc[i].moogSawWaveBtn, + tr( "Click here if you want a moog-saw-wave " + "for current oscillator." ) ); + + m_osc[i].expWaveBtn = new pixmapButton( this ); + m_osc[i].expWaveBtn->move( 203, 120+i*50 ); + m_osc[i].expWaveBtn->setActiveGraphic( embed::getIconPixmap( + "exp_wave_active" ) ); + m_osc[i].expWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "exp_wave_inactive" ) ); + toolTip::add( m_osc[i].expWaveBtn, + tr( "Click here if you want an exponential " + "wave for current oscillator." ) ); + + m_osc[i].whiteNoiseWaveBtn = new pixmapButton( this ); + m_osc[i].whiteNoiseWaveBtn->move( 218, 120+i*50 ); + m_osc[i].whiteNoiseWaveBtn->setActiveGraphic( + embed::getIconPixmap( "white_noise_wave_active" ) ); + m_osc[i].whiteNoiseWaveBtn->setInactiveGraphic( + embed::getIconPixmap( "white_noise_wave_inactive" ) ); + toolTip::add( m_osc[i].whiteNoiseWaveBtn, + tr( "Click here if you want a white-noise for " + "current oscillator." ) ); + + m_osc[i].usrWaveBtn = new pixmapButton( this ); + m_osc[i].usrWaveBtn->move( 233, 120+i*50 ); + m_osc[i].usrWaveBtn->setActiveGraphic( embed::getIconPixmap( + "usr_wave_active" ) ); + m_osc[i].usrWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "usr_wave_inactive" ) ); + toolTip::add( m_osc[i].usrWaveBtn, + tr( "Click here if you want a user-defined " + "wave-shape for current oscillator." ) ); + + QButtonGroup * wave_btn_group = new QButtonGroup( this ); + wave_btn_group->addButton( m_osc[i].sinWaveBtn ); + wave_btn_group->addButton( m_osc[i].triangleWaveBtn ); + wave_btn_group->addButton( m_osc[i].sawWaveBtn ); + wave_btn_group->addButton( m_osc[i].sqrWaveBtn ); + wave_btn_group->addButton( m_osc[i].moogSawWaveBtn ); + wave_btn_group->addButton( m_osc[i].expWaveBtn ); + wave_btn_group->addButton( m_osc[i].whiteNoiseWaveBtn ); + wave_btn_group->addButton( m_osc[i].usrWaveBtn ); + wave_btn_group->setExclusive( TRUE ); +#ifndef QT4 + wave_btn_group->hide(); +#endif + + if( i == 0 ) + { // Osc 1 + connect( m_osc[i].sinWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc01SinWaveCh( bool ) ) ); + connect( m_osc[i].triangleWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc01TriangleWaveCh( bool ) ) ); + connect( m_osc[i].sawWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc01SawWaveCh( bool ) ) ); + connect( m_osc[i].sqrWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc01SquareWaveCh( bool ) ) ); + connect( m_osc[i].moogSawWaveBtn, + SIGNAL(toggled( bool ) ), this, + SLOT( osc01MoogSawWaveCh( bool ) ) ); + connect( m_osc[i].expWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc01ExpWaveCh( bool ) ) ); + connect( m_osc[i].whiteNoiseWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc01WhiteNoiseCh( bool ) ) ); + connect( m_osc[i].usrWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc01UserDefWaveCh( bool ) ) ); + connect( m_osc[i].usrWaveBtn, + SIGNAL( doubleClicked() ), this, + SLOT( osc01UserDefWaveDblClick() ) ); + } + else if( i == 1 ) + { // Osc 2 + connect( m_osc[i].sinWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc02SinWaveCh( bool ) ) ); + connect( m_osc[i].triangleWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc02TriangleWaveCh( bool ) ) ); + connect( m_osc[i].sawWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc02SawWaveCh( bool ) ) ); + connect( m_osc[i].sqrWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc02SquareWaveCh( bool ) ) ); + connect( m_osc[i].moogSawWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc02MoogSawWaveCh( bool ) ) ); + connect( m_osc[i].expWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc02ExpWaveCh( bool ) ) ); + connect( m_osc[i].whiteNoiseWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc02WhiteNoiseCh( bool ) ) ); + connect( m_osc[i].usrWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc02UserDefWaveCh( bool ) ) ); + connect( m_osc[i].usrWaveBtn, + SIGNAL( doubleClicked() ), this, + SLOT( osc02UserDefWaveDblClick() ) ); + } + else if( i == 2 ) + { // Osc 3 + connect( m_osc[i].sinWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc03SinWaveCh( bool ) ) ); + connect( m_osc[i].triangleWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc03TriangleWaveCh( bool ) ) ); + connect( m_osc[i].sawWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc03SawWaveCh( bool ) ) ); + connect( m_osc[i].sqrWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc03SquareWaveCh( bool ) ) ); + connect( m_osc[i].moogSawWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc03MoogSawWaveCh( bool ) ) ); + connect( m_osc[i].expWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc03ExpWaveCh( bool ) ) ); + connect( m_osc[i].whiteNoiseWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc03WhiteNoiseCh( bool ) ) ); + connect( m_osc[i].usrWaveBtn, + SIGNAL( toggled( bool ) ), this, + SLOT( osc03UserDefWaveCh( bool ) ) ); + connect( m_osc[i].usrWaveBtn, + SIGNAL( doubleClicked() ), this, + SLOT( osc03UserDefWaveDblClick() ) ); + } + } +} + + + + +tripleOscillator::~tripleOscillator() +{ +} + + + + +void tripleOscillator::saveSettings( QDomDocument & _doc, + QDomElement & _parent ) +{ + QDomElement to_de = _doc.createElement( nodeName() ); + to_de.setAttribute( "modalgo1", QString::number( m_modulationAlgo1 ) ); + to_de.setAttribute( "modalgo2", QString::number( m_modulationAlgo2 ) ); + + for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) + { + QString is = QString::number( i ); + to_de.setAttribute( "vol" + is, QString::number( + m_osc[i].volKnob->value() ) ); + to_de.setAttribute( "pan" + is, QString::number( + m_osc[i].panKnob->value() ) ); + to_de.setAttribute( "coarse" + is, QString::number( + m_osc[i].coarseKnob->value() ) ); + to_de.setAttribute( "finel" + is, QString::number( + m_osc[i].fineLKnob->value() ) ); + to_de.setAttribute( "finer" + is, QString::number( + m_osc[i].fineRKnob->value() ) ); + to_de.setAttribute( "phoffset" + is, QString::number( + m_osc[i].phaseOffsetKnob->value() ) ); + to_de.setAttribute( "stphdetun" + is, QString::number( + m_osc[i].stereoPhaseDetuningKnob->value() ) ); + to_de.setAttribute( "wavetype" + is, QString::number( + m_osc[i].waveShape ) ); + to_de.setAttribute( "userwavefile" + is, + m_osc[i].m_sampleBuffer.audioFile() ); + } + + _parent.appendChild( to_de ); +} + + + + +void tripleOscillator::loadSettings( const QDomElement & _this ) +{ + m_modulationAlgo1 = static_cast( + _this.attribute( "modalgo1" ).toInt() ); + m_modulationAlgo2 = static_cast( + _this.attribute( "modalgo2" ).toInt() ); + + getModulationButton( m_modulationAlgo1, 1 )->setChecked( TRUE ); + getModulationButton( m_modulationAlgo2, 2 )->setChecked( TRUE ); + + for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) + { + QString is = QString::number( i ); + m_osc[i].volKnob->setValue( _this.attribute( "vol" + is ). + toFloat() ); + m_osc[i].panKnob->setValue( _this.attribute( "pan" + is ). + toFloat() ); + m_osc[i].coarseKnob->setValue( _this.attribute( "coarse" + is ). + toFloat() ); + m_osc[i].fineLKnob->setValue( _this.attribute( "finel" + is ). + toFloat() ); + m_osc[i].fineRKnob->setValue( _this.attribute( "finer" + is ). + toFloat() ); + m_osc[i].phaseOffsetKnob->setValue( _this.attribute( + "phoffset" + is ).toFloat() ); + m_osc[i].stereoPhaseDetuningKnob->setValue( _this.attribute( + "stphdetun" + is ).toFloat() ); + m_osc[i].m_sampleBuffer.setAudioFile( _this.attribute( + "userwavefile" + is ) ); + switch( _this.attribute( "wavetype" + is ).toInt() ) + { + case oscillator::TRIANGLE_WAVE: + m_osc[i].triangleWaveBtn->setChecked( TRUE ); + break; + case oscillator::SAW_WAVE: + m_osc[i].sawWaveBtn->setChecked( TRUE ); + break; + case oscillator::SQUARE_WAVE: + m_osc[i].sqrWaveBtn->setChecked( TRUE ); + break; + case oscillator::MOOG_SAW_WAVE: + m_osc[i].moogSawWaveBtn->setChecked( TRUE ); + break; + case oscillator::EXP_WAVE: + m_osc[i].expWaveBtn->setChecked( TRUE ); + break; + case oscillator::WHITE_NOISE_WAVE: + m_osc[i].whiteNoiseWaveBtn->setChecked( TRUE ); + break; + case oscillator::USER_DEF_WAVE: + toolTip::add( m_osc[i].usrWaveBtn, + m_osc[i].m_sampleBuffer.audioFile() ); + m_osc[i].usrWaveBtn->setChecked( TRUE ); + break; + case oscillator::SIN_WAVE: + default: + m_osc[i].sinWaveBtn->setChecked( TRUE ); + break; + } + } +} + + + + +QString tripleOscillator::nodeName( void ) const +{ + return( tripleoscillator_plugin_descriptor.name ); +} + + + + +void tripleOscillator::playNote( notePlayHandle * _n ) +{ + if( _n->totalFramesPlayed() == 0 ) + { + float freq = getChannelTrack()->frequency( _n ); + + oscillator * oscs_l[NUM_OF_OSCILLATORS]; + oscillator * oscs_r[NUM_OF_OSCILLATORS]; + + for( Sint8 i = NUM_OF_OSCILLATORS-1; i >= 0; --i ) + { + + float osc_detuning_l = pow( 2.0, ( + (float)m_osc[i].coarseKnob->value() * 100.0f + + (float)m_osc[i].fineLKnob->value() ) / 1200.0f); + float osc_detuning_r = pow( 2.0, ( + (float)m_osc[i].coarseKnob->value() * 100.0f + + (float)m_osc[i].fineRKnob->value() ) / 1200.0f); + + float vol_fac_l = ( m_osc[i].panKnob->value() + + PANNING_RIGHT ) / 100.0f; + float vol_fac_r = ( PANNING_RIGHT - + m_osc[i].panKnob->value() ) / + 100.0f; + + if( vol_fac_l > 1.0f ) + { + vol_fac_l = 1.0f; + } + if( vol_fac_r > 1.0f ) + { + vol_fac_r = 1.0f; + } + + vol_fac_l *= m_osc[i].volKnob->value() / 100.0f; + vol_fac_r *= m_osc[i].volKnob->value() / 100.0f; + + // the third oscs needs no sub-oscs... + if( i == 2 ) + { + oscs_l[i] = oscillator::createOsc( + m_osc[i].waveShape, + oscillator::MIX, + freq*osc_detuning_l, + static_cast( + m_osc[i].phaseOffsetKnob->value() + + m_osc[i].stereoPhaseDetuningKnob->value() ), + vol_fac_l ); + oscs_r[i] = oscillator::createOsc( + m_osc[i].waveShape, + oscillator::MIX, + freq*osc_detuning_r, + static_cast( + m_osc[i].phaseOffsetKnob->value() ), + vol_fac_r ); + } + else + { + oscs_l[i] = oscillator::createOsc( + m_osc[i].waveShape, + getModulationAlgo( i + 1 ), + freq*osc_detuning_l, + static_cast( + m_osc[i].phaseOffsetKnob->value() + + m_osc[i].stereoPhaseDetuningKnob->value() ), + vol_fac_l, oscs_l[i + 1] ); + oscs_r[i] = oscillator::createOsc( + m_osc[i].waveShape, + getModulationAlgo( i + 1 ), + freq*osc_detuning_r, + static_cast( + m_osc[i].phaseOffsetKnob->value() ), + vol_fac_r, + oscs_r[i + 1] ); + } + + if( m_osc[i].waveShape == oscillator::USER_DEF_WAVE ) + { + oscs_l[i]->setUserWave( + m_osc[i].m_sampleBuffer.data(), + m_osc[i].m_sampleBuffer.frames() ); + oscs_r[i]->setUserWave( + m_osc[i].m_sampleBuffer.data(), + m_osc[i].m_sampleBuffer.frames() ); + } + + } + + _n->m_pluginData = new oscPtr; + static_cast( _n->m_pluginData )->oscLeft = oscs_l[0]; + static_cast< oscPtr *>( _n->m_pluginData )->oscRight = + oscs_r[0]; + } + + oscillator * osc_l = static_cast( _n->m_pluginData )->oscLeft; + oscillator * osc_r = static_cast( _n->m_pluginData + )->oscRight; + + const Uint32 frames = mixer::inst()->framesPerAudioBuffer(); + sampleFrame * buf = bufferAllocator::alloc( frames ); + + osc_l->update( buf, frames, 0 ); + osc_r->update( buf, frames, 1 ); + + getChannelTrack()->processAudioBuffer( buf, frames, _n ); + + bufferAllocator::free( buf ); +} + + + + +void tripleOscillator::deleteNotePluginData( notePlayHandle * _n ) +{ + if( _n->m_pluginData == NULL ) + { + return; + } + delete static_cast( static_cast( + _n->m_pluginData )->oscLeft ); + delete static_cast( static_cast( + _n->m_pluginData )->oscRight ); + delete static_cast( _n->m_pluginData ); +} + + + + +// now follows all the stupid UI-Code... + +void tripleOscillator::setModulationAlgo( + oscillator::modulationAlgos _new_modulation_algo, int _n ) +{ + if( _n == 1 ) + { + m_modulationAlgo1 = _new_modulation_algo; + } + else + { + m_modulationAlgo2 = _new_modulation_algo; + } + + songEditor::inst()->setModified(); +} + + + + +oscillator::modulationAlgos tripleOscillator::getModulationAlgo( int _n ) +{ + if( _n == 1 ) + { + return( m_modulationAlgo1 ); + } + else + { + return( m_modulationAlgo2 ); + } +} + + + + +void tripleOscillator::doSinWaveBtn( oscillatorData * _osc ) +{ + _osc->waveShape = oscillator::SIN_WAVE; + songEditor::inst()->setModified(); +} + + + + +void tripleOscillator::doTriangleWaveBtn( oscillatorData * _osc ) +{ + _osc->waveShape = oscillator::TRIANGLE_WAVE; + songEditor::inst()->setModified(); +} + + + + +void tripleOscillator::doSawWaveBtn( oscillatorData * _osc ) +{ + _osc->waveShape = oscillator::SAW_WAVE; + songEditor::inst()->setModified(); +} + + + + +void tripleOscillator::doSqrWaveBtn( oscillatorData * _osc ) +{ + _osc->waveShape = oscillator::SQUARE_WAVE; + songEditor::inst()->setModified(); +} + + + + +void tripleOscillator::doMoogSawWaveBtn( oscillatorData * _osc ) +{ + _osc->waveShape = oscillator::MOOG_SAW_WAVE; + songEditor::inst()->setModified(); +} + + + + +void tripleOscillator::doExpWaveBtn( oscillatorData * _osc ) +{ + _osc->waveShape = oscillator::EXP_WAVE; + songEditor::inst()->setModified(); +} + + + + +void tripleOscillator::doWhiteNoiseWaveBtn( oscillatorData * _osc ) +{ + _osc->waveShape = oscillator::WHITE_NOISE_WAVE; + songEditor::inst()->setModified(); +} + + + + +void tripleOscillator::doUsrWaveBtn( oscillatorData * _osc ) +{ + _osc->waveShape = oscillator::USER_DEF_WAVE; + songEditor::inst()->setModified(); +} + + + +// Slots for Osc 1 +void tripleOscillator::osc01SinWaveCh( bool _on ) +{ + if( _on ) doSinWaveBtn( &m_osc[0] ); +} + +void tripleOscillator::osc01TriangleWaveCh( bool _on ) +{ + if( _on ) doTriangleWaveBtn( &m_osc[0] ); +} + +void tripleOscillator::osc01SawWaveCh( bool _on ) +{ + if( _on ) doSawWaveBtn( &m_osc[0] ); +} + +void tripleOscillator::osc01SquareWaveCh( bool _on ) +{ + if( _on ) doSqrWaveBtn( &m_osc[0] ); +} + +void tripleOscillator::osc01MoogSawWaveCh( bool _on ) +{ + if( _on ) doMoogSawWaveBtn( &m_osc[0] ); +} + +void tripleOscillator::osc01ExpWaveCh( bool _on ) +{ + if( _on ) doExpWaveBtn( &m_osc[0] ); +} + +void tripleOscillator::osc01WhiteNoiseCh( bool _on ) +{ + if( _on ) doWhiteNoiseWaveBtn( &m_osc[0] ); +} + +void tripleOscillator::osc01UserDefWaveCh( bool _on ) +{ + if( _on ) doUsrWaveBtn( &m_osc[0] ); +} + +void tripleOscillator::osc01UserDefWaveDblClick( void ) +{ + QString af = m_osc[0].m_sampleBuffer.openAudioFile(); + if( af != "" ) + { + m_osc[0].m_sampleBuffer.setAudioFile( af ); +/*#ifndef QT4 + toolTip::remove( m_osc[0].usrWaveBtn ); +#endif*/ + toolTip::add( m_osc[0].usrWaveBtn, + m_osc[0].m_sampleBuffer.audioFile() ); + } +} + + + +// Slots for Osc 2 +void tripleOscillator::osc02SinWaveCh( bool _on ) +{ + if( _on ) doSinWaveBtn( &m_osc[1] ); +} + +void tripleOscillator::osc02TriangleWaveCh( bool _on ) +{ + if( _on ) doTriangleWaveBtn( &m_osc[1] ); +} + +void tripleOscillator::osc02SawWaveCh( bool _on ) +{ + if( _on ) doSawWaveBtn( &m_osc[1] ); +} + +void tripleOscillator::osc02SquareWaveCh( bool _on ) +{ + if( _on ) doSqrWaveBtn( &m_osc[1] ); +} + +void tripleOscillator::osc02MoogSawWaveCh( bool _on ) +{ + if( _on ) doMoogSawWaveBtn( &m_osc[1] ); +} + +void tripleOscillator::osc02ExpWaveCh( bool _on ) +{ + if( _on ) doExpWaveBtn( &m_osc[1] ); +} + +void tripleOscillator::osc02WhiteNoiseCh( bool _on ) +{ + if( _on ) doWhiteNoiseWaveBtn( &m_osc[1] ); +} + +void tripleOscillator::osc02UserDefWaveCh( bool _on ) +{ + if( _on ) doUsrWaveBtn( &m_osc[1] ); +} + +void tripleOscillator::osc02UserDefWaveDblClick( void ) +{ + QString af = m_osc[1].m_sampleBuffer.openAudioFile(); + if( af != "" ) + { + m_osc[1].m_sampleBuffer.setAudioFile( af ); +/*#ifndef QT4 + toolTip::remove( m_osc[1].usrWaveBtn ); +#endif*/ + toolTip::add( m_osc[1].usrWaveBtn, + m_osc[1].m_sampleBuffer.audioFile() ); + } +} + + +// Slots for Osc 3 +void tripleOscillator::osc03SinWaveCh( bool _on ) +{ + if( _on ) doSinWaveBtn( &m_osc[2] ); +} + +void tripleOscillator::osc03TriangleWaveCh( bool _on ) +{ + if( _on ) doTriangleWaveBtn( &m_osc[2] ); +} + +void tripleOscillator::osc03SawWaveCh( bool _on ) +{ + if( _on ) doSawWaveBtn( &m_osc[2] ); +} + +void tripleOscillator::osc03SquareWaveCh( bool _on ) +{ + if( _on ) doSqrWaveBtn( &m_osc[2] ); +} + +void tripleOscillator::osc03MoogSawWaveCh( bool _on ) +{ + if( _on ) doMoogSawWaveBtn( &m_osc[2] ); +} + +void tripleOscillator::osc03ExpWaveCh( bool _on ) +{ + if( _on ) doExpWaveBtn( &m_osc[2] ); +} + +void tripleOscillator::osc03WhiteNoiseCh( bool _on ) +{ + if( _on ) doWhiteNoiseWaveBtn( &m_osc[2] ); +} + +void tripleOscillator::osc03UserDefWaveCh( bool _on ) +{ + if( _on ) doUsrWaveBtn( &m_osc[2] ); +} + +void tripleOscillator::osc03UserDefWaveDblClick( void ) +{ + QString af = m_osc[2].m_sampleBuffer.openAudioFile(); + if( af != "" ) + { + m_osc[2].m_sampleBuffer.setAudioFile( af ); +/*#ifndef QT4 + toolTip::remove( m_osc[2].usrWaveBtn ); +#endif*/ + toolTip::add( m_osc[2].usrWaveBtn, + m_osc[2].m_sampleBuffer.audioFile() ); + } +} + + + + +void tripleOscillator::fm1BtnToggled( bool _on ) +{ + if( _on ) setModulationAlgo( oscillator::FREQ_MODULATION, 1 ); +} + + + +void tripleOscillator::am1BtnToggled( bool _on ) +{ + if( _on ) setModulationAlgo( oscillator::AMP_MODULATION, 1 ); +} + + + +void tripleOscillator::mix1BtnToggled( bool _on ) +{ + if( _on ) setModulationAlgo( oscillator::MIX, 1 ); +} + + + +void tripleOscillator::sync1BtnToggled( bool _on ) +{ + if( _on ) setModulationAlgo( oscillator::SYNC, 1 ); +} + + + +void tripleOscillator::fm2BtnToggled( bool _on ) +{ + if( _on ) setModulationAlgo( oscillator::FREQ_MODULATION, 2 ); +} + + + +void tripleOscillator::am2BtnToggled( bool _on ) +{ + if( _on ) setModulationAlgo( oscillator::AMP_MODULATION, 2 ); +} + + + +void tripleOscillator::mix2BtnToggled( bool _on ) +{ + if( _on ) setModulationAlgo( oscillator::MIX, 2 ); +} + + + +void tripleOscillator::sync2BtnToggled( bool _on ) +{ + if( _on ) setModulationAlgo( oscillator::SYNC, 2 ); +} + + + + +pixmapButton * tripleOscillator::getModulationButton( + oscillator::modulationAlgos _modulation_algo, int _n ) +{ + if( _n == 1 ) + { + switch( _modulation_algo ) + { + case oscillator::FREQ_MODULATION: return( m_fm1OscBtn ); + case oscillator::AMP_MODULATION: return( m_am1OscBtn ); + case oscillator::MIX: return( m_mix1OscBtn ); + case oscillator::SYNC: return( m_sync1OscBtn ); + } + } + else + { + switch( _modulation_algo ) + { + case oscillator::FREQ_MODULATION: return( m_fm2OscBtn ); + case oscillator::AMP_MODULATION: return( m_am2OscBtn ); + case oscillator::MIX: return( m_mix2OscBtn ); + case oscillator::SYNC: return( m_sync2OscBtn ); + } + } +#ifdef LMMS_DEBUG + // there's something really not ok, if this case occurs, so let's exit + assert( 1 != 1 ); +#endif + return( NULL ); +} + + + + +extern "C" +{ + +// neccessary for getting instance out of shared lib +plugin * lmms_plugin_main( void * _data ) +{ + return( new tripleOscillator( + static_cast( _data ) ) ); +} + +} + + +#undef setChecked + + +#include "triple_oscillator.moc" + diff --git a/plugins/triple_oscillator/triple_oscillator.h b/plugins/triple_oscillator/triple_oscillator.h new file mode 100644 index 000000000..cb8b873b0 --- /dev/null +++ b/plugins/triple_oscillator/triple_oscillator.h @@ -0,0 +1,167 @@ +/* + * triple_oscillator.h - declaration of class tripleOscillator a powerful + * instrument-plugin with 3 oscillators + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef _TRIPLE_OSCILLATOR_H +#define _TRIPLE_OSCILLATOR_H + + +#include "instrument.h" +#include "oscillator.h" +#include "sample_buffer.h" + + +class knob; +class pixmapButton; +class notePlayHandle; + + +const int NUM_OF_OSCILLATORS = 3; + + +class tripleOscillator : public instrument +{ + Q_OBJECT +public: + tripleOscillator( channelTrack * _channel ) FASTCALL; + virtual ~tripleOscillator(); + + virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); + + + virtual void FASTCALL saveSettings( QDomDocument & _doc, + QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + + virtual QString nodeName( void ) const; + + +protected slots: + // Slots for Osc 1 + void osc01SinWaveCh( bool _on ); + void osc01TriangleWaveCh( bool _on ); + void osc01SawWaveCh( bool _on ); + void osc01SquareWaveCh( bool _on ); + void osc01MoogSawWaveCh( bool _on ); + void osc01ExpWaveCh( bool _on ); + void osc01WhiteNoiseCh( bool _on ); + void osc01UserDefWaveCh( bool _on ); + void osc01UserDefWaveDblClick( void ); + + // Slots for Osc 2 + void osc02SinWaveCh( bool _on ); + void osc02TriangleWaveCh( bool _on ); + void osc02SawWaveCh( bool _on ); + void osc02SquareWaveCh( bool _on ); + void osc02MoogSawWaveCh( bool _on ); + void osc02ExpWaveCh( bool _on ); + void osc02WhiteNoiseCh( bool _on ); + void osc02UserDefWaveCh( bool _on ); + void osc02UserDefWaveDblClick( void ); + + // Slots for Osc 3 + void osc03SinWaveCh( bool _on ); + void osc03TriangleWaveCh( bool _on ); + void osc03SawWaveCh( bool _on ); + void osc03SquareWaveCh( bool _on ); + void osc03MoogSawWaveCh( bool _on ); + void osc03ExpWaveCh( bool _on ); + void osc03WhiteNoiseCh( bool _on ); + void osc03UserDefWaveCh( bool _on ); + void osc03UserDefWaveDblClick( void ); + + // modulation-type-button slots + void fm1BtnToggled( bool _on ); + void am1BtnToggled( bool _on ); + void mix1BtnToggled( bool _on ); + void sync1BtnToggled( bool _on ); + + void fm2BtnToggled( bool _on ); + void am2BtnToggled( bool _on ); + void mix2BtnToggled( bool _on ); + void sync2BtnToggled( bool _on ); + + +private: + channelTrack * m_channelTrack; + + struct oscillatorData + { + oscillator::waveShapes waveShape; + knob * volKnob; + knob * panKnob; + knob * coarseKnob; + knob * fineLKnob; + knob * fineRKnob; + knob * phaseOffsetKnob; + knob * stereoPhaseDetuningKnob; + pixmapButton * sinWaveBtn; + pixmapButton * triangleWaveBtn; + pixmapButton * sawWaveBtn; + pixmapButton * sqrWaveBtn; + pixmapButton * moogSawWaveBtn; + pixmapButton * expWaveBtn; + pixmapButton * whiteNoiseWaveBtn; + pixmapButton * usrWaveBtn; + sampleBuffer m_sampleBuffer; + } m_osc[NUM_OF_OSCILLATORS]; + + struct oscPtr + { + oscillator * oscLeft; + oscillator * oscRight; + } ; + + + void FASTCALL doSinWaveBtn( oscillatorData * _osc ); + void FASTCALL doTriangleWaveBtn( oscillatorData * _osc ); + void FASTCALL doSawWaveBtn( oscillatorData * _osc ); + void FASTCALL doSqrWaveBtn( oscillatorData * _osc ); + void FASTCALL doMoogSawWaveBtn( oscillatorData * _osc ); + void FASTCALL doExpWaveBtn( oscillatorData * _osc ); + void FASTCALL doWhiteNoiseWaveBtn( oscillatorData * _osc ); + void FASTCALL doUsrWaveBtn( oscillatorData * _osc ); + pixmapButton * FASTCALL getModulationButton( + oscillator::modulationAlgos _modulation_algo, int _n ); + void FASTCALL setModulationAlgo( + oscillator::modulationAlgos _new_modulation_algo, int _n ); + oscillator::modulationAlgos FASTCALL getModulationAlgo( int _n ); + + + pixmapButton * m_fm1OscBtn; + pixmapButton * m_am1OscBtn; + pixmapButton * m_mix1OscBtn; + pixmapButton * m_sync1OscBtn; + pixmapButton * m_fm2OscBtn; + pixmapButton * m_am2OscBtn; + pixmapButton * m_mix2OscBtn; + pixmapButton * m_sync2OscBtn; + + oscillator::modulationAlgos m_modulationAlgo1; + oscillator::modulationAlgos m_modulationAlgo2; + +} ; + + +#endif diff --git a/plugins/vestige/Makefile.am b/plugins/vestige/Makefile.am new file mode 100644 index 000000000..d2a4cc944 --- /dev/null +++ b/plugins/vestige/Makefile.am @@ -0,0 +1,35 @@ +AUTOMAKE_OPTIONS = foreign 1.4 + + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I. + + +AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="vestige" + + +%.moc: ./%.h + $(MOC) -o $@ $< + + +MOC_FILES = ./vestige.moc + +BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h +EMBEDDED_RESOURCES = $(wildcard *png) + +./embedded_resources.h: $(EMBEDDED_RESOURCES) + $(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@ + +EXTRA_DIST = $(EMBEDDED_RESOURCES) + + +CLEANFILES = $(MOC_FILES) ./embedded_resources.h + + + +pkglib_LTLIBRARIES= libvestige.la + +libvestige_la_SOURCES = vestige.cpp vestige.h +# libvestige_la_LIBADD = -lfst + +$(libvestige_la_SOURCES): ./embedded_resources.h + diff --git a/plugins/vestige/artwork.png b/plugins/vestige/artwork.png new file mode 100644 index 000000000..25893f82e Binary files /dev/null and b/plugins/vestige/artwork.png differ diff --git a/plugins/vestige/logo.png b/plugins/vestige/logo.png new file mode 100644 index 000000000..87403dda5 Binary files /dev/null and b/plugins/vestige/logo.png differ diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp new file mode 100644 index 000000000..3f7caf28e --- /dev/null +++ b/plugins/vestige/vestige.cpp @@ -0,0 +1,860 @@ +/* + * vestige.cpp - instrument-plugin for hosting VST-plugins + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +#include +#include +#include +#include + +#else + +#include +#include +#include +#include +#include +#include + +#endif + + +#include "vestige.h" +#include "channel_track.h" +#include "note_play_handle.h" +#include "buffer_allocator.h" +#include "mixer.h" +#include "song_editor.h" +#include "instrument_play_handle.h" +#include "pixmap_button.h" +#include "tooltip.h" +#include "spc_bg_hndl_widget.h" + + +#include "embed.cpp" + + +extern "C" +{ + +plugin::descriptor vestige_plugin_descriptor = +{ + STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ), + "VeSTige", + QT_TRANSLATE_NOOP( "plugin", + "experimental VST-hoster for using VST-plugins " + "within LMMS" ), + "Tobias Doerffel ", + 0x0100, + plugin::INSTRUMENT, + PLUGIN_NAME::findEmbeddedData( "logo.png" ) +} ; + +} + + +bool vestigeInstrument::s_initialized = FALSE; +bool vestigeInstrument::s_threadAdopted = FALSE; +QPixmap * vestigeInstrument::s_artwork = NULL; + + +vestigeInstrument::vestigeInstrument( channelTrack * _channel_track ) : + instrument( _channel_track, vestige_plugin_descriptor.public_name ), + specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ), + m_handle( NULL ), + m_fst( NULL ) +{ + if( s_artwork == NULL ) + { + s_artwork = new QPixmap( PLUGIN_NAME::getIconPixmap( + "artwork" ) ); + } +#ifdef QT4 + QPalette pal; + pal.setBrush( backgroundRole(), *s_artwork); + setPalette( pal ); +#else + setErasePixmap( *s_artwork ); +#endif + + m_openPluginButton = new pixmapButton( this ); + m_openPluginButton->setCheckable( FALSE ); + m_openPluginButton->setCursor( PointingHandCursor ); + m_openPluginButton->move( 200, 70 ); + m_openPluginButton->setActiveGraphic( embed::getIconPixmap( + "project_open_down" ) ); + m_openPluginButton->setInactiveGraphic( embed::getIconPixmap( + "project_open" ) ); + m_openPluginButton->setBgGraphic( getBackground( + m_openPluginButton ) ); + connect( m_openPluginButton, SIGNAL( clicked() ), this, + SLOT( openPlugin() ) ); + toolTip::add( m_openPluginButton, tr( "Open other VST-plugin" ) ); + +#ifdef QT4 + m_openPluginButton->setWhatsThis( +#else + QWhatsThis::add( m_openPluginButton, +#endif + tr( "Click here, if you want to open another VST-plugin. After " + "clicking on this button, a file-open-dialog appears " + "and you can select your file." ) ); + + if( s_initialized == FALSE ) + { + if( fst_init( fst_signal_handler ) ) + { + // TODO: message-box + return; + } + s_initialized = TRUE; + } + // now we need a play-handle which cares for calling play() + instrumentPlayHandle * iph = new instrumentPlayHandle( this ); + mixer::inst()->addPlayHandle( iph ); +} + + + + +vestigeInstrument::~vestigeInstrument() +{ + // this single call automates the rest of cleanup like trashing our + // play-handle and so on + invalidate(); + closePlugin(); +} + + + + +void vestigeInstrument::loadSettings( const QDomElement & _this ) +{ +} + + + + +void vestigeInstrument::saveSettings( QDomDocument & _doc, + QDomElement & _parent ) +{ + QDomElement vst_de = _doc.createElement( nodeName() ); + _parent.appendChild( vst_de ); +} + + + + +QString vestigeInstrument::nodeName( void ) const +{ + return( vestige_plugin_descriptor.name ); +} + + + + +void vestigeInstrument::setParameter( const QString & _param, + const QString & _value ) +{ + if( _param == "plugin" ) + { + closePlugin(); + + m_plugin = _value; + if( ( m_handle = fst_load( +#ifdef QT4 + m_plugin.constData().toAscii() +#else + m_plugin.ascii() +#endif + ) ) == NULL ) + { + QMessageBox::information( this, + tr( "Failed loading plugin" ), + tr( "The VST-plugin %1 couldn't be " + "loaded for some reason." ).arg( + m_plugin ), + QMessageBox::Ok ); + return; + } + if( ( m_fst = fst_instantiate( m_handle, hostCallback, + this ) ) == NULL ) + { + QMessageBox::information( this, + tr( "Failed instantiating plugin" ), + tr( "Couldn't create an instance of " + "VST-plugin %1 for some " + "reason." ).arg( m_plugin ), + QMessageBox::Ok ); + fst_unload( m_handle ); + m_handle = NULL; + return; + } + + // set sample-rate and blocksize + m_fst->plugin->dispatcher( m_fst->plugin, effSetSampleRate, 0, + 0, NULL, mixer::inst()->sampleRate() ); + m_fst->plugin->dispatcher( m_fst->plugin, effSetBlockSize, 0, + mixer::inst()->framesPerAudioBuffer(), + NULL, 0.0f ); + // set program to zero + m_fst->plugin->dispatcher( m_fst->plugin, effSetProgram, 0, 0, + NULL, 0.0f ); + // resume + m_fst->plugin->dispatcher( m_fst->plugin, effMainsChanged, 0, + 1, NULL, 0.0f ); +/* if( fst_run_editor( m_fst ) ) + { + printf( "VeSTige: cannot create editor\n" ); + }*/ + int vst_version = m_fst->plugin->dispatcher( m_fst->plugin, + effGetVstVersion, 0, 0, + NULL, 0.0f ); + if( vst_version < 2 ) + { + QMessageBox::information( this, + tr( "VST-plugin too old" ), + tr( "The version of VST-plugin %1 " + "is smaller than 2, which " + "isn't supported." ).arg( + m_plugin ), + QMessageBox::Ok ); + return; + } +/* printf("WID:%d %d\n", (int)fst_get_XID( m_fst ), + (int)QWidget::find( fst_get_XID( m_fst ) ) );*/ + + //printf("%d\n", m_fst->plugin->numParams); + } +} + + + + +void vestigeInstrument::play( void ) +{ + // the very first time, we have to adopt fst-thread + if( !s_threadAdopted ) + { + fst_adopt_thread(); + s_threadAdopted = TRUE; + } + + if( m_handle == NULL || m_fst == NULL ) + { + return; + } + + // first we gonna post all MIDI-events we enqueued so far + if( m_midiEvents.size() ) + { + // since MIDI-events are not received immediately, we have + // to have them stored somewhere even after dispatcher-call, + // so we create static copies of the data and post them + static VstEvents events; + static vvector cur_events; + cur_events = m_midiEvents; + m_midiEvents.clear(); + for( csize i = 0; i < cur_events.size(); ++i ) + { + events.events[i] = (VstEvent *) &cur_events[i]; + } + events.numEvents = cur_events.size(); + events.reserved = 0; + m_fst->plugin->dispatcher( m_fst->plugin, effProcessEvents, + 0, 0, &events, 0.0f ); + } + + // now we're ready to fetch sound from VST-plugin + const Uint32 frames = mixer::inst()->framesPerAudioBuffer(); + + int ch_in = m_fst->plugin->numInputs; + int ch_out = m_fst->plugin->numOutputs; + float * ins[ch_in]; + float * outs[ch_out]; + for( int i = 0; i < ch_in; ++i ) + { + ins[i] = bufferAllocator::alloc( frames ); + } + for( int i = 0; i < ch_out; ++i ) + { + outs[i] = bufferAllocator::alloc( frames ); + } + + if( m_fst->plugin->flags & effFlagsCanReplacing ) + { + m_fst->plugin->processReplacing( m_fst->plugin, ins, outs, + frames ); + + } + else + { + printf("normal process\n"); + //mixer::inst()->clearAudioBuffer( buf, frames ); + m_fst->plugin->process( m_fst->plugin, ins, outs, frames ); + printf("normal process done\n"); + } + + for( int i = 0; i < ch_in; ++i ) + { + bufferAllocator::free( ins[i] ); + } + + // got our data, now we just have to merge the 1/2 out-buffers + sampleFrame * buf = bufferAllocator::alloc( frames ); + Uint8 chnls = tMax( ch_out, DEFAULT_CHANNELS ); + if( chnls != DEFAULT_CHANNELS ) + { + mixer::inst()->clearAudioBuffer( buf, frames ); + } + + for( Uint32 f = 0; f < frames; ++f ) + { + for( Uint8 chnl = 0; chnl < chnls; ++chnl ) + { + buf[f][chnl] = outs[chnl][f]; + } + } + + for( int i = 0; i < ch_out; ++i ) + { + bufferAllocator::free( outs[i] ); + } + + getChannelTrack()->processAudioBuffer( buf, frames, NULL ); + + bufferAllocator::free( buf ); +} + + + + + + +void vestigeInstrument::playNote( notePlayHandle * _n ) +{ + if( _n->totalFramesPlayed() == 0 ) + { + enqueueEvent( midiEvent( NOTE_ON, 0, _n->key(), + _n->getVolume() ), _n->framesAhead() ); + } +} + + + + +void vestigeInstrument::deleteNotePluginData( notePlayHandle * _n ) +{ + enqueueEvent( midiEvent( NOTE_OFF, 0, _n->key(), 0 ) ); +} + + + + +void vestigeInstrument::openPlugin( void ) +{ +#ifdef QT4 + QFileDialog ofd( NULL, tr( "Open VST-plugin" ) ); +#else + QFileDialog ofd( QString::null, QString::null, NULL, "", TRUE ); + ofd.setWindowTitle( tr( "Open VST-plugin" ) ); +#endif + + QString dir; + if( m_plugin != "" ) + { +#ifdef QT4 + dir = QFileInfo( m_plugin ).absolutePath(); +#else + dir = QFileInfo( m_plugin ).dirPath( TRUE ); +#endif + } + else + { + dir = QDir::home().path(); + } + // change dir to position of previously opened file + ofd.setDirectory( dir ); + ofd.setFileMode( QFileDialog::ExistingFiles ); + + // set filters +#ifdef QT4 + QStringList types; + types << tr( "DLL-files (*.dll)" ) + << tr( "EXE-files (*.exe)" ) + ; + ofd.setFilters( types ); +#else + ofd.addFilter( tr( "DLL-files (*.dll)" ) ); + ofd.addFilter( tr( "EXE-files (*.exe)" ) ); + ofd.setSelectedFilter( tr( "DLL-files (*.dll)" ) ); +#endif + if( m_plugin != "" ) + { + // select previously opened file + ofd.selectFile( QFileInfo( m_plugin ).fileName() ); + } + + if ( ofd.exec () == QDialog::Accepted ) + { + if( ofd.selectedFiles().isEmpty() ) + { + return; + } + setParameter( "plugin", ofd.selectedFiles()[0] ); + } +} + + + + +void vestigeInstrument::paintEvent( QPaintEvent * ) +{ +#ifdef QT4 + QPainter p( this ); +#else + QPixmap pm( rect().size() ); + pm.fill( this, rect().topLeft() ); + + QPainter p( &pm, this ); +#endif + + p.drawPixmap( 0, 0, *s_artwork ); + + QString plugin_name = ( m_handle != NULL && m_fst != NULL ) ? + QString( m_handle->name ) + " " + + QString::number( m_fst->plugin->dispatcher( + m_fst->plugin, + effGetVendorVersion, + 0, 0, NULL, 0.0f ) ): + tr( "No VST-plugin loaded" ); + QFont f = p.font(); + f.setBold( TRUE ); + p.setFont( pointSize<10>( f ) ); + p.setPen( QColor( 0, 0, 0 ) ); + + p.drawText( 20, 80, plugin_name ); + + if( m_handle != NULL && m_fst != NULL ) + { + p.setPen( QColor( 64, 128, 64 ) ); + f.setBold( FALSE ); + p.setFont( pointSize<8>( f ) ); + char buf[1024]; + m_fst->plugin->dispatcher( m_fst->plugin, effGetVendorString, + 0, 0, buf, 0 ); + p.drawText( 20, 94, tr( "by" ) + " " + QString( buf ) ); + } +#ifndef QT4 + bitBlt( this, rect().topLeft(), &pm ); +#endif +} + + + + +void vestigeInstrument::closePlugin( void ) +{ + if( m_fst != NULL && m_handle != NULL ) + { + //fst_destroy_editor( m_fst ); + printf( "closing VST-plugin" ); + fst_close( m_fst ); + printf( "unloading VST-plugin" ); + fst_unload( m_handle ); + m_fst = NULL; + m_handle = NULL; + } +} + + + + +void vestigeInstrument::enqueueEvent( const midiEvent & _e, + Uint32 _frames_ahead ) +{ + if( m_handle == NULL || m_fst == NULL ) + { + return; + } + + VstMidiEvent event; + + event.type = kVstMidiType; + event.byteSize = 24; + event.deltaFrames = _frames_ahead; + event.flags = 0; + event.detune = 0; + event.noteLength = 0; + event.noteOffset = 0; + event.noteOffVelocity = 0; + event.reserved1 = 0; + event.reserved2 = 0; + event.midiData[0] = _e.m_type + _e.m_channel; + event.midiData[1] = _e.key(); + event.midiData[2] = _e.velocity(); + event.midiData[3] = 0; + + m_midiEvents.push_back( event ); +} + + + +#define DEBUG_CALLBACKS +#ifdef DEBUG_CALLBACKS +#define SHOW_CALLBACK printf +#else +#define SHOW_CALLBACK(...) +#endif + +long vestigeInstrument::hostCallback( AEffect * _effect, long _opcode, + long _index, long _value, void * _ptr, + float _opt ) +{ + static VstTimeInfo _timeInfo; + + SHOW_CALLBACK( "host-callback, opcode = %d", (int) _opcode ); + + switch( _opcode ) + { + case audioMasterAutomate: + SHOW_CALLBACK( "amc: audioMasterAutomate\n" ); + // index, value, returns 0 + _effect->setParameter( _effect, _index, _opt ); + return( 0 ); + + case audioMasterVersion: + SHOW_CALLBACK( "amc: audioMasterVersion\n" ); + // vst version, currently 2 (0 for older) + return( 2 ); + + case audioMasterCurrentId: + SHOW_CALLBACK( "amc: audioMasterCurrentId\n" ); + // returns the unique id of a plug that's currently + // loading + return( 0 ); + + case audioMasterIdle: + SHOW_CALLBACK ("amc: audioMasterIdle\n"); + // call application idle routine (this will + // call effEditIdle for all open editors too) + _effect->dispatcher( _effect, effEditIdle, 0, 0, NULL, + 0.0f ); + return( 0 ); + + case audioMasterPinConnected: + SHOW_CALLBACK( "amc: audioMasterPinConnected\n" ); + // inquire if an input or output is beeing connected; + // index enumerates input or output counting from zero: + // value is 0 for input and != 0 otherwise. note: the + // return value is 0 for such that older versions + // will always return true. + return( 1 ); + + case audioMasterWantMidi: + SHOW_CALLBACK( "amc: audioMasterWantMidi\n" ); + // is a filter which is currently ignored + return( 0 ); + + case audioMasterGetTime: + SHOW_CALLBACK( "amc: audioMasterGetTime\n" ); + // returns const VstTimeInfo* (or 0 if not supported) + // should contain a mask indicating which + // fields are required (see valid masks above), as some + // items may require extensive conversions + + memset( &_timeInfo, 0, sizeof( _timeInfo ) ); + + //tstate = jack_transport_query (jackvst->client, &jack_pos); + _timeInfo.samplePos = 0; + _timeInfo.sampleRate = mixer::inst()->sampleRate(); + _timeInfo.flags = 0; + _timeInfo.tempo = songEditor::inst()->getBPM(); + _timeInfo.timeSigNumerator = 4;//(long) floor (jack_pos.beats_per_bar); + _timeInfo.timeSigDenominator = 4;//(long) floor (jack_pos.beat_type); + _timeInfo.flags |= (kVstBarsValid|kVstTempoValid); +// if (tstate == JackTransportRolling) { + _timeInfo.flags |= kVstTransportPlaying; +// } + + return( (long)&_timeInfo ); + + case audioMasterProcessEvents: + SHOW_CALLBACK( "amc: audioMasterProcessEvents\n" ); + // VstEvents* in + return( 0 ); + + case audioMasterSetTime: + SHOW_CALLBACK( "amc: audioMasterSetTime\n" ); + // VstTimenfo* in , filter in , not + // supported + + case audioMasterTempoAt: + SHOW_CALLBACK( "amc: audioMasterTempoAt\n" ); + // returns tempo (in bpm * 10000) at sample frame + // location passed in + return( 0 ); + + case audioMasterGetNumAutomatableParameters: + SHOW_CALLBACK( "amc: audioMasterGetNumAutomatable" + "Parameters\n" ); + return( 0 ); + + case audioMasterGetParameterQuantization: + SHOW_CALLBACK( "amc: audioMasterGetParameter\n" + "Quantization\n" ); + // returns the integer value for +1.0 representation, + // or 1 if full single float precision is maintained + // in automation. parameter index in (-1: all, + // any) + return( 0 ); + + case audioMasterIOChanged: + SHOW_CALLBACK( "amc: audioMasterIOChanged\n" ); + // numInputs and/or numOutputs has changed + return( 0 ); + + case audioMasterNeedIdle: + SHOW_CALLBACK( "amc: audioMasterNeedIdle\n" ); + // plug needs idle calls (outside its editor window) + return( 0 ); + + case audioMasterSizeWindow: + // TODO using lmms-main-window-size + SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" ); + // index: width, value: height + return( 0 ); + + case audioMasterGetSampleRate: + // TODO using mixer-call + SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" ); + return( 0 ); + + case audioMasterGetBlockSize: + // TODO using mixer-call + SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" ); + return( 0 ); + + case audioMasterGetInputLatency: + // TODO using mixer-call + SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" ); + return( 0 ); + + case audioMasterGetOutputLatency: + // TODO using mixer-call + SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" ); + return( 0 ); + + case audioMasterGetPreviousPlug: + SHOW_CALLBACK( "amc: audioMasterGetPreviousPlug\n" ); + // input pin in (-1: first to come), returns + // cEffect* + return( 0 ); + + case audioMasterGetNextPlug: + SHOW_CALLBACK( "amc: audioMasterGetNextPlug\n" ); + // output pin in (-1: first to come), returns + // cEffect* + return( 0 ); + + case audioMasterWillReplaceOrAccumulate: + SHOW_CALLBACK( "amc: audioMasterWillReplaceOr" + "Accumulate\n" ); + // returns: 0: not supported, 1: replace, 2: accumulate + return( 0 ); + + case audioMasterGetCurrentProcessLevel: + SHOW_CALLBACK( "amc: audioMasterGetCurrentProcess" + "Level\n" ); + // returns: 0: not supported, + // 1: currently in user thread (gui) + // 2: currently in audio thread (where process is + // called) + // 3: currently in 'sequencer' thread (midi, timer etc) + // 4: currently offline processing and thus in user + // thread + // other: not defined, but probably pre-empting user + // thread. + return( 0 ); + + case audioMasterGetAutomationState: + SHOW_CALLBACK( "amc: audioMasterGetAutomationState\n" ); + // returns 0: not supported, 1: off, 2:read, 3:write, + // 4:read/write offline + return( 0 ); + + case audioMasterOfflineStart: + SHOW_CALLBACK( "amc: audioMasterOfflineStart\n" ); + return( 0 ); + + case audioMasterOfflineRead: + SHOW_CALLBACK( "amc: audioMasterOfflineRead\n" ); + // ptr points to offline structure, see below. + // return 0: error, 1 ok + return( 0 ); + + case audioMasterOfflineWrite: + SHOW_CALLBACK( "amc: audioMasterOfflineWrite\n" ); + // same as read + return( 0 ); + + case audioMasterOfflineGetCurrentPass: + SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrent" + "Pass\n" ); + return( 0 ); + + case audioMasterOfflineGetCurrentMetaPass: + SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrentMeta" + "Pass\n"); + return( 0 ); + + case audioMasterSetOutputSampleRate: + SHOW_CALLBACK( "amc: audioMasterSetOutputSample" + "Rate\n" ); + // for variable i/o, sample rate in + return( 0 ); + + case audioMasterGetSpeakerArrangement: + SHOW_CALLBACK( "amc: audioMasterGetSpeaker" + "Arrangement\n" ); + // (long)input in , output in + return( 0 ); + + case audioMasterGetVendorString: + SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" ); + // fills with a string identifying the vendor + // (max 64 char) + strcpy( (char *) _ptr, "LAD"); + return( 0 ); + + case audioMasterGetProductString: + SHOW_CALLBACK( "amc: audioMasterGetProductString\n" ); + // fills with a string with product name + // (max 64 char) + strcpy( (char *) _ptr, "VeSTige" ); + return( 0 ); + + case audioMasterGetVendorVersion: + SHOW_CALLBACK( "amc: audioMasterGetVendorVersion\n" ); + // TODO + // returns vendor-specific version + return( 1000 ); + + case audioMasterVendorSpecific: + SHOW_CALLBACK( "amc: audioMasterVendorSpecific\n" ); + // no definition, vendor specific handling + return( 0 ); + + case audioMasterSetIcon: + SHOW_CALLBACK( "amc: audioMasterSetIcon\n" ); + // TODO + // void* in , format not defined yet + return( 0 ); + + case audioMasterCanDo: + SHOW_CALLBACK( "amc: audioMasterCanDo\n" ); + // string in ptr, see below + return( 0 ); + + case audioMasterGetLanguage: + SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" ); + // TODO + // see enum + return( 0 ); + + case audioMasterOpenWindow: + SHOW_CALLBACK( "amc: audioMasterOpenWindow\n" ); + // TODO + // returns platform specific ptr + return( 0 ); + + case audioMasterCloseWindow: + SHOW_CALLBACK( "amc: audioMasterCloseWindow\n" ); + // TODO + // close window, platform specific handle in + return( 0 ); + + case audioMasterGetDirectory: + SHOW_CALLBACK( "amc: audioMasterGetDirectory\n" ); + // TODO + // get plug directory, FSSpec on MAC, else char* + return( 0 ); + + case audioMasterUpdateDisplay: + SHOW_CALLBACK( "amc: audioMasterUpdateDisplay\n" ); + // something has changed, update 'multi-fx' display + _effect->dispatcher( _effect, effEditIdle, 0, 0, NULL, + 0.0f ); + return( 0 ); + + case audioMasterBeginEdit: + SHOW_CALLBACK( "amc: audioMasterBeginEdit\n" ); + // begin of automation session (when mouse down), + // parameter index in + return( 0 ); + + case audioMasterEndEdit: + SHOW_CALLBACK( "amc: audioMasterEndEdit\n" ); + // end of automation session (when mouse up), + // parameter index in + return( 0 ); + + case audioMasterOpenFileSelector: + SHOW_CALLBACK( "amc: audioMasterOpenFileSelector\n" ); + // open a fileselector window with VstFileSelect* + // in + return( 0 ); + + default: + SHOW_CALLBACK( "VST master dispatcher: undefed: " + "%d, %d\n", (int) _opcode, + effKeysRequired ); + break; + } + + return( 0 ); +} + + + +extern "C" +{ + +// neccessary for getting instance out of shared lib +plugin * lmms_plugin_main( void * _data ) +{ + return( new vestigeInstrument( static_cast( _data ) ) ); +} + + +} + + +#include "vestige.moc" + diff --git a/plugins/vestige/vestige.h b/plugins/vestige/vestige.h new file mode 100644 index 000000000..4560c9b00 --- /dev/null +++ b/plugins/vestige/vestige.h @@ -0,0 +1,110 @@ +/* + * vestige.h - instrument VeSTige for hosting VST-plugins + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _VESTIGE_H +#define _VESTIGE_H + +#include "instrument.h" +#include "midi.h" + +#ifdef QT4 + +#include + +#else + +#include + +#endif + + +#include +#include + +#include "spc_bg_hndl_widget.h" + + +class pixmapButton; +class QPixmap; + + +class vestigeInstrument : public instrument, public specialBgHandlingWidget +{ + Q_OBJECT +public: + vestigeInstrument( channelTrack * _channel_track ); + virtual ~vestigeInstrument(); + + virtual void play( void ); + + virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); + + + virtual void FASTCALL saveSettings( QDomDocument & _doc, + QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + + virtual QString nodeName( void ) const; + + virtual void FASTCALL setParameter( const QString & _param, + const QString & _value ); + + +protected slots: + void openPlugin( void ); + + +protected: + virtual void paintEvent( QPaintEvent * _pe ); + + +private: + void closePlugin( void ); + + void enqueueEvent( const midiEvent & _e, Uint32 _frames_ahead = 0 ); + + static long hostCallback( AEffect *, long, long, long, void *, float ); + + + static bool s_initialized; + static bool s_threadAdopted; + static QPixmap * s_artwork; + + + FSTHandle * m_handle; + FST * m_fst; + + vvector m_midiEvents; + + + pixmapButton * m_openPluginButton; + + QString m_plugin; + + +} ; + + +#endif diff --git a/resources/add_sample_track.png b/resources/add_sample_track.png index 9643357a2..5f00cdd0e 100644 Binary files a/resources/add_sample_track.png and b/resources/add_sample_track.png differ diff --git a/resources/project_export.png b/resources/project_export.png index e23861bf7..3fc6f401c 100644 Binary files a/resources/project_export.png and b/resources/project_export.png differ diff --git a/resources/project_new.png b/resources/project_new.png index ba32d712d..20f7423e0 100644 Binary files a/resources/project_new.png and b/resources/project_new.png differ diff --git a/resources/project_open.png b/resources/project_open.png index 0e306f254..5bae07f5e 100644 Binary files a/resources/project_open.png and b/resources/project_open.png differ diff --git a/resources/project_save.png b/resources/project_save.png index 677ce2097..d92724ea8 100644 Binary files a/resources/project_save.png and b/resources/project_save.png differ diff --git a/resources/project_saveas.png b/resources/project_saveas.png index fa310a145..1741664c4 100644 Binary files a/resources/project_saveas.png and b/resources/project_saveas.png differ diff --git a/resources/sample_track.png b/resources/sample_track.png index c8eeee881..0f3837c26 100644 Binary files a/resources/sample_track.png and b/resources/sample_track.png differ diff --git a/src/audio/audio_alsa.cpp b/src/audio/audio_alsa.cpp index 83e3a6c41..f5a5f5732 100644 --- a/src/audio/audio_alsa.cpp +++ b/src/audio/audio_alsa.cpp @@ -175,13 +175,13 @@ int audioALSA::handleError( int _err ) void audioALSA::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ) + float _master_gain ) { outputSampleType * outbuf = bufferAllocator::alloc( _frames * channels() ); bufferAllocator::autoCleaner<> ac( outbuf ); - convertToS16( _ab, _frames, _master_output, outbuf, + convertToS16( _ab, _frames, _master_gain, outbuf, m_littleEndian != isLittleEndian() ); Uint32 frame = 0; diff --git a/src/audio/audio_device.cpp b/src/audio/audio_device.cpp index 2a1769d3c..18ce18ad2 100644 --- a/src/audio/audio_device.cpp +++ b/src/audio/audio_device.cpp @@ -70,7 +70,7 @@ audioDevice::~audioDevice() void audioDevice::writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, - Uint32 _src_sample_rate, float _master_output ) + Uint32 _src_sample_rate, float _master_gain ) { // make sure, no other thread is accessing device lock(); @@ -82,12 +82,12 @@ void audioDevice::writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, _frames * channels() ); resample( _ab, _frames, temp, _src_sample_rate, m_sampleRate ); writeBufferToDev( temp, _frames * m_sampleRate / - _src_sample_rate, _master_output ); + _src_sample_rate, _master_gain ); bufferAllocator::free( temp ); } else { - writeBufferToDev( _ab, _frames, _master_output ); + writeBufferToDev( _ab, _frames, _master_gain ); } // release lock unlock(); @@ -240,7 +240,7 @@ LP_FILTER_COEFFS[tap] * lp_hist[( oldest + tap ) % LP_FILTER_TAPS][chnl]; int FASTCALL audioDevice::convertToS16( surroundSampleFrame * _ab, - Uint32 _frames, float _master_output, + Uint32 _frames, float _master_gain, outputSampleType * _output_buffer, bool _convert_endian ) { @@ -251,7 +251,7 @@ int FASTCALL audioDevice::convertToS16( surroundSampleFrame * _ab, ( _output_buffer + frame * channels() )[chnl] = static_cast( mixer::clip( _ab[frame][chnl] * - _master_output ) * + _master_gain ) * OUTPUT_SAMPLE_MULTIPLIER ); } } diff --git a/src/audio/audio_file_ogg.cpp b/src/audio/audio_file_ogg.cpp index c8704309a..27d4177f8 100644 --- a/src/audio/audio_file_ogg.cpp +++ b/src/audio/audio_file_ogg.cpp @@ -186,7 +186,7 @@ bool audioFileOgg::startEncoding( void ) void FASTCALL audioFileOgg::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ) + float _master_gain ) { int eos = 0; @@ -197,7 +197,7 @@ void FASTCALL audioFileOgg::writeBufferToDev( surroundSampleFrame * _ab, { for( Uint8 chnl = 0; chnl < channels(); ++chnl ) { - buffer[chnl][frame] = _ab[frame][chnl] * _master_output; + buffer[chnl][frame] = _ab[frame][chnl] * _master_gain; } } diff --git a/src/audio/audio_file_wave.cpp b/src/audio/audio_file_wave.cpp index 89bebb546..2da1a90b3 100644 --- a/src/audio/audio_file_wave.cpp +++ b/src/audio/audio_file_wave.cpp @@ -88,11 +88,11 @@ bool audioFileWave::startEncoding( void ) void FASTCALL audioFileWave::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ) + float _master_gain ) { outputSampleType * outbuf = bufferAllocator::alloc( _frames * channels() ); - int bytes = convertToS16( _ab, _frames, _master_output, outbuf, + int bytes = convertToS16( _ab, _frames, _master_gain, outbuf, !isLittleEndian() ); writeData( outbuf, bytes ); diff --git a/src/audio/audio_jack.cpp b/src/audio/audio_jack.cpp index a0619f25c..59706fcc4 100644 --- a/src/audio/audio_jack.cpp +++ b/src/audio/audio_jack.cpp @@ -214,7 +214,7 @@ audioJACK::~audioJACK() void audioJACK::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ) + float _master_gain ) { m_bufMutex.lock(); @@ -228,7 +228,7 @@ void audioJACK::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, _frames ); for( Uint32 frame = 0; frame < _frames; ++frame ) { - buf[frame] = _ab[frame][chnl] * _master_output; + buf[frame] = _ab[frame][chnl] * _master_gain; } bufset b = { buf, _frames } ; bufs.push_back( b ); @@ -246,7 +246,10 @@ void audioJACK::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, #ifdef HAVE_UNISTD_H #ifdef HAVE_USLEEP // just wait and give cpu-time to other processes - usleep( 200 ); + // tobydox 20051019: causes LMMS to hang up when locking + // several other mutexes, so skip it + //usleep( 200 ); + #endif #endif } @@ -264,6 +267,8 @@ int audioJACK::processCallback( jack_nframes_t _nframes, void * _udata ) #endif jack_transport_state_t ts = jack_transport_query( _this->m_client, NULL ); + _this->m_bufMutex.lock(); + if( ts != JackTransportRolling ) { // always decrease frame-sync-var as we would do it if running @@ -276,6 +281,7 @@ int audioJACK::processCallback( jack_nframes_t _nframes, void * _udata ) { _this->m_frameSync = 0; } + _this->m_bufMutex.unlock(); return( 0 ); } @@ -289,7 +295,6 @@ int audioJACK::processCallback( jack_nframes_t _nframes, void * _udata ) _this->m_outputPorts[ch], _nframes ); } - _this->m_bufMutex.lock(); jack_nframes_t done = 0; while( done < _nframes ) diff --git a/src/audio/audio_oss.cpp b/src/audio/audio_oss.cpp index 717674c0a..9e7ba5de0 100644 --- a/src/audio/audio_oss.cpp +++ b/src/audio/audio_oss.cpp @@ -278,11 +278,11 @@ QString audioOSS::probeDevice( void ) void audioOSS::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ) + float _master_gain ) { outputSampleType * outbuf = bufferAllocator::alloc( _frames * channels() ); - int bytes = convertToS16( _ab, _frames, _master_output, outbuf, + int bytes = convertToS16( _ab, _frames, _master_gain, outbuf, m_convertEndian ); write( m_audioFD, outbuf, bytes ); diff --git a/src/audio/audio_sdl.cpp b/src/audio/audio_sdl.cpp index 0d4e9f0ef..15b8481c6 100644 --- a/src/audio/audio_sdl.cpp +++ b/src/audio/audio_sdl.cpp @@ -125,10 +125,10 @@ audioSDL::~audioSDL() void audioSDL::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_output ) + float _master_gain ) { m_bufMutex.lock(); - convertToS16( _ab, _frames, _master_output, m_buffer, + convertToS16( _ab, _frames, _master_gain, m_buffer, m_convertEndian ); m_bufMutex.unlock(); // before returning make sure, callback was called, so we're synced diff --git a/src/core/bb_editor.cpp b/src/core/bb_editor.cpp index ba5d0c46e..24264ebcc 100644 --- a/src/core/bb_editor.cpp +++ b/src/core/bb_editor.cpp @@ -294,14 +294,6 @@ void bbEditor::keyPressEvent( QKeyEvent * _ke ) -void bbEditor::wheelEvent( QWheelEvent * _we ) -{ - lmmsMainWin::inst()->workspace()->wheelEvent( _we ); -} - - - - void bbEditor::resizeEvent( QResizeEvent * _re ) { updateBackground(); diff --git a/src/core/config_mgr.cpp b/src/core/config_mgr.cpp index 3ada40fe4..59a210bcc 100644 --- a/src/core/config_mgr.cpp +++ b/src/core/config_mgr.cpp @@ -163,10 +163,19 @@ configManager::configManager( void ) : m_lmmsDataDir( qApp->applicationDirPath().section( '/', 0, -2 ) + "/share/lmms/" ), #else - // hardcode since qt 3.0 doesn't know something like - // applicationDirPath and implmeneting own function would be senseless - // since real support for qt 3.0 is senseless too ;-) + // hardcode since qt < 3.2 doesn't know something like + // applicationDirPath and implementing own function would be senseless + // since real support for qt < 3.2 is senseless too ;-) m_lmmsDataDir( "/usr/share/lmms" ), +#endif +#if QT_VERSION >= 0x030200 + m_lmmsPluginDir( qApp->applicationDirPath().section( '/', 0, -2 ) + + "/lib/lmms/" ), +#else + // hardcode since qt < 3.2 doesn't know something like + // applicationDirPath and implementing own function would be senseless + // since real support for qt < 3.2 is senseless too ;-) + m_lmmsPluginDir( "/usr/lib/lmms" ), #endif m_currentPage( 0 ) { diff --git a/src/core/envelope_tab_widget.cpp b/src/core/envelope_tab_widget.cpp index 9a7c9b177..87c7f8e0f 100644 --- a/src/core/envelope_tab_widget.cpp +++ b/src/core/envelope_tab_widget.cpp @@ -153,10 +153,7 @@ envelopeTabWidget::envelopeTabWidget( channelTrack * _channel_track, m_filterComboBox->addItem( tr( "Notch" ) ); m_filterComboBox->addItem( tr( "Allpass" ) ); m_filterComboBox->addItem( tr( "Moog" ) ); - m_filterComboBox->addItem( tr( "Moog 2" ) ); m_filterComboBox->addItem( tr( "2x LowPass" ) ); - m_filterComboBox->addItem( tr( "2x Moog" ) ); - m_filterComboBox->addItem( tr( "2x Moog 2" ) ); #ifdef QT4 m_filterComboBox->setWhatsThis( diff --git a/src/core/instrument.cpp b/src/core/instrument.cpp new file mode 100644 index 000000000..302f3a0a9 --- /dev/null +++ b/src/core/instrument.cpp @@ -0,0 +1,93 @@ +/* + * instrument.cpp - base-class for all instrument-plugins (synths, samplers etc) + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "instrument.h" +#include "channel_track.h" +#include "dummy_instrument.h" + + +instrument::instrument( channelTrack * _channel_track, const QString & _name ) : + QWidget( _channel_track->pluginParent() ), + plugin( _name, INSTRUMENT ), + m_channelTrack( _channel_track ), + m_valid( TRUE ) +{ + setFixedSize( 250, 250 ); +} + + + + +instrument::~instrument() +{ +} + + + + +void instrument::play( void ) +{ +} + + + + +void instrument::playNote( notePlayHandle * ) +{ +} + + + + +void instrument::deleteNotePluginData( notePlayHandle * ) +{ +} + + + + +Uint32 instrument::beatLen( notePlayHandle * ) const +{ + return( 0 ); +} + + + + +instrument * instrument::instantiate( const QString & _plugin_name, + channelTrack * _channel_track ) +{ + plugin * p = plugin::instantiate( _plugin_name, _channel_track ); + // check whether instantiated plugin is an instrument + if( dynamic_cast( p ) != NULL ) + { + // everything ok, so return pointer + return( dynamic_cast( p ) ); + } + + // not quite... so delete plugin and return dummy instrument + delete p; + return( new dummyInstrument( _channel_track ) ); +} + diff --git a/src/core/main.cpp b/src/core/main.cpp index f34bca727..2431adcbf 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -163,6 +163,7 @@ int main( int argc, char * * argv ) e->show(); e->exportBtnClicked(); } + return( app.exec() ); } diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index a81bdcaea..77f6c905e 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -211,27 +211,6 @@ void mixer::run( void ) // while we're acting... m_safetySyncMutex.lock(); -/* following code is faster but unstable since using iterators - while deleting from vector is dangerous and often leads to - undefined results... - - playHandleVector::iterator it = m_playHandles.begin(); - while( it != m_playHandles.end() ) - { - if( ( *it )->done() ) - { - // delete all play-handles which have - // played completely now - delete *it; - m_playHandles.erase( it ); - } - else - { - // play all uncompletely-played play-handles... - ( *it )->play(); - ++it; - } - }*/ csize idx = 0; while( idx < m_playHandles.size() ) { diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp new file mode 100644 index 000000000..cfc1b2d4c --- /dev/null +++ b/src/core/plugin.cpp @@ -0,0 +1,175 @@ +/* + * plugin.cpp - implemenation of plugin-class including plugin-loader + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_DLFCN_H +#include +#endif + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include + +#else + +#include +#include + +#endif + + +#include "plugin.h" +#include "mixer.h" +#include "config_mgr.h" +#include "dummy_plugin.h" + + + +plugin::plugin( const QString & _public_name, pluginTypes _type ) : + settings(), + m_publicName( _public_name ), + m_type( _type ) +{ +} + + + + +plugin::~plugin() +{ +} + + + + +void plugin::setParameter( const QString &, const QString & ) +{ +} + + + + +QString plugin::getParameter( const QString & ) +{ + return( "" ); +} + + + + +plugin * plugin::instantiate( const QString & _plugin_name, void * _data ) +{ +#ifdef HAVE_DLFCN_H + void * handle = dlopen( QString( "lib" + _plugin_name + ".so" ). +#ifdef QT4 + toAscii().constData() +#else + ascii() +#endif + , RTLD_LAZY ); + if( handle == NULL ) + { + QMessageBox::information( NULL, + mixer::tr( "Plugin not found" ), + mixer::tr( "The %1-plugin wasn't found!" + ).arg( _plugin_name ), + QMessageBox::Ok | + QMessageBox::Default ); + return( new dummyPlugin() ); + } + dlerror(); + instantiationHook inst_hook = ( instantiationHook )( dlsym( handle, + "lmms_plugin_main" ) ); + char * error = dlerror(); + if( error != NULL ) + { + printf( "%s\n", error ); + QMessageBox::information( NULL, + mixer::tr( "Error while loading plugin" ), + mixer::tr( "Failed loading plugin \"%1\"!" + ).arg( _plugin_name ), + QMessageBox::Ok | + QMessageBox::Default ); + return( new dummyPlugin() ); + } + plugin * inst = inst_hook( _data ); + //dlclose( handle ); + return( inst ); +#endif + return( new dummyPlugin() ); +} + + + + +void plugin::getDescriptorsOfAvailPlugins( vvector & _plugin_descs ) +{ + QDir directory( configManager::inst()->pluginDir() ); + const QFileInfoList * list = directory.entryInfoList( "*.so" ); + if( list == NULL ) + { + return; + } + for( QFileInfoList::iterator file = list->begin(); + file != list->end(); ++file ) + { + void * handle = dlopen( ( *file )->absFilePath().latin1(), + RTLD_LAZY ); + char * msg = dlerror(); + if( msg != NULL || handle == NULL ) + { + printf( "plugin-loader: %s\n", msg ); + continue; + } + void * foo = dlsym( handle, "lmms_plugin_main" ); + msg = dlerror(); + if( msg != NULL || foo == NULL ) + { + printf( "plugin-loader: %s\n", msg ); + continue; + } + QString desc_name = ( *file )->fileName().mid( 3 ).section( + '.', 0, 0 ) + "_plugin_descriptor"; + descriptor * plugin_desc = + (descriptor *) dlsym( handle, desc_name.ascii() ); + msg = dlerror(); + if( msg != NULL || plugin_desc == NULL ) + { + printf( "plugin-loader: %s\n", msg ); + continue; + } + _plugin_descs.push_back( *plugin_desc ); + //dlclose( handle ); + } + +} + + + diff --git a/src/core/plugin_browser.cpp b/src/core/plugin_browser.cpp new file mode 100644 index 000000000..75ebc169e --- /dev/null +++ b/src/core/plugin_browser.cpp @@ -0,0 +1,248 @@ +/* + * plugin_browser.cpp - implementation of the plugin-browser + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +/*#include */ +#include + +#else + +#include +#include +/*#include */ +#include + +#endif + + +#include "plugin_browser.h" +#include "embed.h" +#include "debug.h" +#include "gui_templates.h" +#include "string_pair_drag.h" + + + +pluginBrowser::pluginBrowser( QWidget * _parent ) : + sideBarWidget( tr( "Instrument plugins" ), + embed::getIconPixmap( "plugins" ), _parent ) +{ + setWindowTitle( tr( "Plugin browser" ) ); + m_view = new QWidget( contentParent() ); + //m_view->setFrameShape( QFrame::NoFrame ); + + addContentWidget( m_view ); + + QVBoxLayout * view_layout = new QVBoxLayout( m_view, 5, 10 ); + + + QLabel * hint = new QLabel( tr( "You can drag an instrument-plugin " + "into either the Song-Editor, the " + "Beat+Bassline Editor or just into a " + "channel-window or on the " + "corresponding channel-button." ), + m_view ); + hint->setFont( pointSize<8>( hint->font() ) ); + hint->setAlignment( hint->alignment() | WordBreak ); + view_layout->addWidget( hint ); + + plugin::getDescriptorsOfAvailPlugins( m_pluginDescriptors ); + + for( vvector::iterator it = + m_pluginDescriptors.begin(); + it != m_pluginDescriptors.end(); ++it ) + { + pluginDescWidget * p = new pluginDescWidget( *it, m_view ); + p->show(); + view_layout->addWidget( p ); + } + view_layout->addStretch(); + show(); +} + + + + +pluginBrowser::~pluginBrowser() +{ +} + + + + + + + +pluginDescWidget::pluginDescWidget( const plugin::descriptor & _pd, + QWidget * _parent ) : + QWidget( _parent ), + m_pluginDescriptor( _pd ), + m_logo(), + m_mouseOver( FALSE ) +{ + m_logo.loadFromData( _pd.logo.data, _pd.logo.size ); + setFixedHeight( 60 ); + setMouseTracking( TRUE ); +#ifndef QT4 + setBackgroundMode( Qt::NoBackground ); +#endif + setCursor( PointingHandCursor ); +} + + + + +pluginDescWidget::~pluginDescWidget() +{ +} + + + + +void pluginDescWidget::paintEvent( QPaintEvent * ) +{ + QColor fill_color( 192, 192, 192 ); + if( m_mouseOver ) + { + fill_color = QColor( 224, 224, 224 ); + } + +#ifdef QT4 + QPainter p( this ); + p.fillRect( rect(), fill_color ); +#else + // create pixmap for whole widget + QPixmap pm( rect().size() ); + pm.fill( fill_color ); + + // and a painter for it + QPainter p( &pm ); +#endif + p.setPen( QColor( 64, 64, 64 ) ); + p.drawRect( rect() ); + p.drawPixmap( 4, 4, m_logo ); + + QFont f = pointSize<8>( p.font() ); + f.setBold( TRUE ); + p.setFont( f ); + p.drawText( 58, 14, m_pluginDescriptor.public_name ); + + f.setBold( FALSE ); + p.setFont( pointSize<7>( f ) ); + QStringList words = QStringList::split( ' ', + plugin::tr( m_pluginDescriptor.description ) ); + for( QStringList::iterator it = words.begin(); it != words.end(); ++it ) + { + if( ( *it ).contains( '-' ) ) + { + QStringList splitted_word = QStringList::split( '-', + *it ); + QStringList::iterator orig_it = it; + for( QStringList::iterator it2 = splitted_word.begin(); + it2 != splitted_word.end(); ++it2 ) + { + if( it2 == splitted_word.fromLast() ) + { + words.insert( it, *it2 ); + } + else + { + words.insert( it, *it2 + "-" ); + ++it; + } + } + words.erase( orig_it ); + --it; + } + } + + int y = 26; + int avail_width = width() - 58 - 5; + QString s; + for( QStringList::iterator it = words.begin(); it != words.end(); ++it ) + { + if( p.fontMetrics().width( s + *it + " " ) >= avail_width ) + { + p.drawText( 58, y, s ); + y += 10; + s = ""; + } + s += *it; + if( ( *it ).right( 1 ) != "-" ) + { + s += " "; + } + } + p.drawText( 58, y, s ); + +#ifndef QT4 + // blit drawn pixmap to actual widget + bitBlt( this, rect().topLeft(), &pm ); +#endif +} + + + + +void pluginDescWidget::mousePressEvent( QMouseEvent * _me ) +{ + if( _me->button() == Qt::LeftButton ) + { + new stringPairDrag( "plugin", m_pluginDescriptor.name, m_logo, + this ); + m_mouseOver = FALSE; + update(); + } +} + + + + +void pluginDescWidget::mouseMoveEvent( QMouseEvent * _me ) +{ + bool new_mouse_over = rect().contains( _me->pos() ); + if( new_mouse_over != m_mouseOver ) + { + m_mouseOver = new_mouse_over; + update(); + } +} + + + + +void pluginDescWidget::mouseReleaseEvent( QMouseEvent * _me ) +{ + mouseMoveEvent( _me ); +} + + + +#include "plugin_browser.moc" + diff --git a/src/core/preset_preview_play_handle.cpp b/src/core/preset_preview_play_handle.cpp index 9cc4f2eab..0829aa7e9 100644 --- a/src/core/preset_preview_play_handle.cpp +++ b/src/core/preset_preview_play_handle.cpp @@ -115,7 +115,7 @@ presetPreviewPlayHandle::presetPreviewPlayHandle( multimediaProject mmp( _preset_file ); if( s_globalChannelTrack == NULL ) { - track * t = track::createTrack( track::CHANNEL_TRACK, + track * t = track::create( track::CHANNEL_TRACK, blindTrackContainer::inst() ); s_globalChannelTrack = dynamic_cast( t ); #ifdef LMMS_DEBUG diff --git a/src/core/song_editor.cpp b/src/core/song_editor.cpp index 289d57ce2..4673e4e83 100644 --- a/src/core/song_editor.cpp +++ b/src/core/song_editor.cpp @@ -351,16 +351,6 @@ songEditor::songEditor() : /* edit_tb->setPaletteBackgroundPixmap( embed::getIconPixmap( "toolbar_bg" ) ); edit_tb->setErasePixmap( embed::getIconPixmap( "toolbar_bg" ) );*/ -#ifdef QT4 - a = edit_tb->addAction( embed::getIconPixmap( "add_channel_track" ), "", - this, SLOT( addChannelTrack() ) ); - a->setToolTip( tr( "Add channel-track" ) ); -#else - m_addChannelTrackButton = new QToolButton( embed::getIconPixmap( - "add_channel_track" ), "", "", - this, SLOT( addChannelTrack() ), - edit_tb ); -#endif #ifdef QT4 a = edit_tb->addAction( embed::getIconPixmap( "add_bb_track" ), "", this, SLOT( addBBTrack() ) ); @@ -414,7 +404,6 @@ songEditor::songEditor() : toolTip::add( m_playButton, tr( "Play/pause song (Space)" ) ); toolTip::add( m_stopButton, tr( "Stop playing song (Space)" ) ); - toolTip::add( m_addChannelTrackButton, tr( "Add channel-track" ) ); toolTip::add( m_addBBTrackButton, tr( "Add beat/bassline" ) ); toolTip::add( m_addSampleTrackButton, tr( "Add sample-track" ) ); toolTip::add( m_insertTactButton, tr( "Insert tact at current tact " @@ -609,7 +598,6 @@ void songEditor::scrolled( int _new_pos ) void songEditor::wheelEvent( QWheelEvent * _we ) { - _we->accept(); if( m_controlPressed ) { if( _we->delta() > 0 ) @@ -636,6 +624,12 @@ void songEditor::wheelEvent( QWheelEvent * _we ) m_leftRightScroll->setValue( m_leftRightScroll->value() - _we->delta() / 30 ); } + else + { + _we->ignore(); + return; + } + _we->accept(); } @@ -1290,24 +1284,9 @@ void songEditor::removeTact( void ) -void songEditor::addChannelTrack( void ) -{ - channelTrack * t = dynamic_cast< channelTrack * >( - track::createTrack( track::CHANNEL_TRACK, this ) ); -#ifdef LMMS_DEBUG - assert( t != NULL ); -#endif - t->loadPlugin( "tripleoscillator" ); - t->toggledChannelButton( TRUE ); - t->show(); -} - - - - void songEditor::addBBTrack( void ) { - track * t = track::createTrack( track::BB_TRACK, this ); + track * t = track::create( track::BB_TRACK, this ); if( dynamic_cast( t ) != NULL ) { dynamic_cast( t )->clickedTrackLabel(); @@ -1319,7 +1298,7 @@ void songEditor::addBBTrack( void ) void songEditor::addSampleTrack( void ) { - (void) track::createTrack( track::SAMPLE_TRACK, this ); + (void) track::create( track::SAMPLE_TRACK, this ); } @@ -1435,14 +1414,14 @@ void songEditor::createNewProject( void ) clearProject(); track * t; - t = track::createTrack( track::CHANNEL_TRACK, this ); - dynamic_cast< channelTrack * >( t )->loadPlugin( + t = track::create( track::CHANNEL_TRACK, this ); + dynamic_cast< channelTrack * >( t )->loadInstrument( "tripleoscillator" ); - track::createTrack( track::SAMPLE_TRACK, this ); - t = track::createTrack( track::CHANNEL_TRACK, bbEditor::inst() ); - dynamic_cast< channelTrack * >( t )->loadPlugin( + track::create( track::SAMPLE_TRACK, this ); + t = track::create( track::CHANNEL_TRACK, bbEditor::inst() ); + dynamic_cast< channelTrack * >( t )->loadInstrument( "tripleoscillator" ); - track::createTrack( track::BB_TRACK, this ); + track::create( track::BB_TRACK, this ); setBPM( DEFAULT_BPM ); m_masterVolumeSlider->setValue( 100 ); diff --git a/src/core/track.cpp b/src/core/track.cpp index 674288ac6..ebbc48e52 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -607,10 +607,10 @@ trackWidget::trackWidget( track * _track, QWidget * _parent ) : "", &m_trackOperationsWidget ); deltr_btn->setGeometry( 1, 1+TRACK_OP_BTN_HEIGHT, TRACK_OP_BTN_WIDTH, TRACK_OP_BTN_HEIGHT ); - connect( deltr_btn, SIGNAL( clicked() ), this, SLOT( deleteTrack() ) ); + connect( deltr_btn, SIGNAL( clicked() ), this, SLOT( removeTrack() ) ); connect( deltr_btn, SIGNAL( clicked() ), deltr_btn, SLOT( clearFocus() ) ); - toolTip::add( deltr_btn, tr( "Delete this track" ) ); + toolTip::add( deltr_btn, tr( "Remove this track" ) ); QPushButton * muptr_btn = new QPushButton( embed::getIconPixmap( "arp_up_on", 12, 12 ), @@ -718,7 +718,7 @@ void trackWidget::cloneTrack( void ) -void trackWidget::deleteTrack( void ) +void trackWidget::removeTrack( void ) { m_track->getTrackContainer()->removeTrack( m_track ); } @@ -873,7 +873,7 @@ track::~track() -track * FASTCALL track::createTrack( trackTypes _tt, trackContainer * _tc ) +track * FASTCALL track::create( trackTypes _tt, trackContainer * _tc ) { switch( _tt ) { @@ -891,10 +891,10 @@ track * FASTCALL track::createTrack( trackTypes _tt, trackContainer * _tc ) -track * FASTCALL track::createTrack( const QDomElement & _this, +track * FASTCALL track::create( const QDomElement & _this, trackContainer * _tc ) { - track * t = createTrack( static_cast( _this.attribute( + track * t = create( static_cast( _this.attribute( "type" ).toInt() ), _tc ); #ifdef LMMS_DEBUG assert( t != NULL ); @@ -906,13 +906,13 @@ track * FASTCALL track::createTrack( const QDomElement & _this, -track * FASTCALL track::cloneTrack( track * _track ) +track * FASTCALL track::clone( track * _track ) { QDomDocument doc; QDomElement parent = doc.createElement( "clone" ); _track->saveSettings( doc, parent ); QDomElement e = parent.firstChild().toElement(); - return( createTrack( e, _track->getTrackContainer() ) ); + return( create( e, _track->getTrackContainer() ) ); } diff --git a/src/core/track_container.cpp b/src/core/track_container.cpp index 25627f27c..6c191d907 100644 --- a/src/core/track_container.cpp +++ b/src/core/track_container.cpp @@ -51,7 +51,9 @@ #include "lmms_main_win.h" #include "mixer.h" #include "song_editor.h" - +#include "string_pair_drag.h" +#include "channel_track.h" +#include "mmp.h" @@ -69,15 +71,9 @@ trackContainer::trackContainer() : lmmsMainWin::inst()->workspace()->addWindow( this ); #endif - m_scrollArea = new QScrollArea( this ); - m_scrollArea->setFrameStyle( QFrame::NoFrame ); - m_scrollArea->setHorizontalScrollBarPolicy( -#ifdef QT4 - Qt::ScrollBarAlwaysOff -#else - QScrollArea::AlwaysOff -#endif - ); + m_scrollArea = new scrollArea( this ); + + setAcceptDrops( TRUE ); } @@ -157,7 +153,7 @@ void trackContainer::loadSettings( const QDomElement & _this ) if( node.isElement() ) { - track::createTrack( node.toElement(), this ); + track::create( node.toElement(), this ); } node = node.nextSibling(); } @@ -176,7 +172,7 @@ void trackContainer::loadSettings( const QDomElement & _this ) void trackContainer::cloneTrack( track * _track ) { - track::cloneTrack( _track ); + track::clone( _track ); } @@ -372,6 +368,41 @@ void trackContainer::resizeEvent( QResizeEvent * ) +void trackContainer::dragEnterEvent( QDragEnterEvent * _dee ) +{ + stringPairDrag::processDragEnterEvent( _dee, "preset,plugin" ); +} + + + + +void trackContainer::dropEvent( QDropEvent * _de ) +{ + QString type = stringPairDrag::decodeKey( _de ); + QString value = stringPairDrag::decodeValue( _de ); + if( type == "plugin" ) + { + channelTrack * ct = dynamic_cast( + track::create( track::CHANNEL_TRACK, + this ) ); + ct->loadInstrument( value ); + ct->toggledChannelButton( TRUE ); + } + else if( type == "preset" ) + { + multimediaProject mmp( value ); + channelTrack * ct = dynamic_cast( + track::create( track::CHANNEL_TRACK, + this ) ); + ct->loadTrackSpecificSettings( mmp.content().firstChild(). + toElement() ); + ct->toggledChannelButton( TRUE ); + } +} + + + + void trackContainer::updateScrollArea( void ) { m_scrollArea->resize( tMax( m_scrollArea->parentWidget()->width() - @@ -384,6 +415,45 @@ void trackContainer::updateScrollArea( void ) +trackContainer::scrollArea::scrollArea( trackContainer * _parent ) : + QScrollArea( _parent ) +{ + setFrameStyle( QFrame::NoFrame ); + setHorizontalScrollBarPolicy( +#ifdef QT4 + Qt::ScrollBarAlwaysOff +#else + QScrollArea::AlwaysOff +#endif + ); +} + + + + +trackContainer::scrollArea::~scrollArea() +{ +} + + + + +void trackContainer::scrollArea::wheelEvent( QWheelEvent * _we ) +{ + // always pass wheel-event to parent-widget (song-editor + // bb-editor etc.) because they might want to use it for zooming + // or scrolling left/right if a modifier-key is pressed, otherwise + // they do not accept it and we pass it up to QScrollArea + dynamic_cast( parentWidget() )->wheelEvent( _we ); + if( !_we->isAccepted() ) + { + QScrollArea::wheelEvent( _we ); + } +} + + + + #include "track_container.moc" #undef setValue diff --git a/src/lib/buffer_allocator.cpp b/src/lib/buffer_allocator.cpp index f49391937..6e5cde08d 100644 --- a/src/lib/buffer_allocator.cpp +++ b/src/lib/buffer_allocator.cpp @@ -188,7 +188,7 @@ void * bufferAllocator::allocBytes( Uint32 _bytes ) } - // nothing so far, so we'll alloc a new (aligned) buf + // got nothing so far, so we'll alloc a new (aligned) buf bufDesc d = { FALSE, new char[_bytes + BUFFER_ALIGN], NULL, _bytes, 0 }; d.buf = (void *)( (size_t) d.origPtr + ( BUFFER_ALIGN - ( (size_t) d.origPtr & diff --git a/src/lib/embed.cpp b/src/lib/embed.cpp index 9bd9934bb..ae2d5c336 100644 --- a/src/lib/embed.cpp +++ b/src/lib/embed.cpp @@ -43,9 +43,15 @@ #include "config_mgr.h" + +#ifndef PLUGIN_NAME namespace embed +#else +namespace PLUGIN_NAME +#endif { + #include "embedded_resources.h" @@ -55,10 +61,10 @@ QPixmap getIconPixmap( const char * _name, int _w, int _h ) { QString name = QString( _name ) + ".png"; #ifdef QT4 - const embedDesc & e = findEmbeddedData( + const embed::descriptor & e = findEmbeddedData( name.toAscii().constData() ); #else - const embedDesc & e = findEmbeddedData( name.ascii() ); + const embed::descriptor & e = findEmbeddedData( name.ascii() ); #endif // not found? if( QString( e.name ) != name ) @@ -88,13 +94,12 @@ QPixmap getIconPixmap( const char * _name, int _w, int _h ) QString getText( const char * _name ) { - const embedDesc & e = findEmbeddedData( _name ); + const embed::descriptor & e = findEmbeddedData( _name ); return( QString::fromLatin1( (const char *) e.data, e.size ) ); } - void loadTranslation( const QString & _tname ) { QTranslator * t = new QTranslator( 0 ); @@ -103,9 +108,10 @@ void loadTranslation( const QString & _tname ) #if QT_VERSION >= 0x030100 #ifdef QT4 - const embedDesc & e = findEmbeddedData( name.toAscii().constData() ); + const embed::descriptor & e = findEmbeddedData( + name.toAscii().constData() ); #else - const embedDesc & e = findEmbeddedData( name.ascii() ); + const embed::descriptor & e = findEmbeddedData( name.ascii() ); #endif // not found? if( QString( e.name ) != name ) @@ -126,3 +132,4 @@ void loadTranslation( const QString & _tname ) } + diff --git a/src/lib/ladspa_manager.cpp b/src/lib/ladspa_manager.cpp index 8d8d0afa0..88bdba73d 100644 --- a/src/lib/ladspa_manager.cpp +++ b/src/lib/ladspa_manager.cpp @@ -23,26 +23,31 @@ */ +#include "ladspa_manager.h" + +#ifdef LADSPA_SUPPORT + + #ifdef QT4 #include #include -#include #else #include #include -#include #endif -#include + +#ifdef HAVE_DLFCN_H #include +#endif + #include -#include "ladspa_manager.h" ladspaManager * ladspaManager::s_instanceOfMe = NULL; @@ -55,19 +60,25 @@ ladspaManager::ladspaManager( void ) // TODO Need to move the search path definition to the config file to have // more control over where it tries to find the plugins. - QStringList ladspaDirectories = QStringList::split( QString( ":" ), + QStringList ladspaDirectories = QStringList::split( ':', QString( getenv( "LADSPA_PATH" ) ) ); // set default-directory if nothing is specified... if( ladspaDirectories.isEmpty() ) { ladspaDirectories.push_back( "/usr/lib/ladspa" ); + ladspaDirectories.push_back( "/usr/local/lib/ladspa" ); } for( QStringList::iterator it = ladspaDirectories.begin(); it != ladspaDirectories.end(); ++it ) { QDir directory( ( *it ) ); const QFileInfoList * list = directory.entryInfoList(); - + // if directory doesn't exist or isn't readable, we get NULL which + // would crash LMMS... + if( list == NULL ) + { + continue; + } for( QFileInfoList::iterator file = list->begin(); file != list->end(); ++file ) { @@ -842,3 +853,6 @@ void FASTCALL ladspaManager::cleanup( const ladspaKey & _plugin, } } + +#endif + diff --git a/src/lib/string_pair_drag.cpp b/src/lib/string_pair_drag.cpp new file mode 100644 index 000000000..aecc8d292 --- /dev/null +++ b/src/lib/string_pair_drag.cpp @@ -0,0 +1,112 @@ +/* + * string_pair_drag.cpp - class stringPairDrag which provides general support + * for drag'n'drop of string-pairs + * + * Linux MultiMedia Studio + * Copyright (c) 2004-2005 Tobias Doerffel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "string_pair_drag.h" + + + +stringPairDrag::stringPairDrag( const QString & _key, const QString & _value, + const QPixmap & _icon, QWidget * _w ) : +#ifdef QT4 + QDrag( _w ) +#else + QStoredDrag( "lmms/stringpair", _w ) +#endif +{ + setPixmap( _icon ); + QString txt = _key + ":" + _value; +#ifdef QT4 + QMimeData * m = new QMimeData(); + m->setData( "lmms/stringpair", txt.toAscii() ); + setMimeData( m ); + start( /*Qt::CopyAction*/ Qt::IgnoreAction ); +#else + setEncodedData( txt.utf8() ); + drag(); +#endif +} + + + + +stringPairDrag::~stringPairDrag() +{ + // TODO: do we have to delete anything??? +} + + + + +void stringPairDrag::processDragEnterEvent( QDragEnterEvent * _dee, + const QString & _allowed_keys ) +{ +#ifdef QT4 + if( !_dee->mimeData()->hasFormat( "lmms/stringpair" ) ) + { + return; + } + QString txt = _dee->mimeData()->data(); +#else + QString txt = _dee->encodedData( "lmms/stringpair" ); +#endif + bool accepted = QStringList::split( ',', _allowed_keys ).contains( + txt.section( ':', 0, 0 ) ); +#ifdef QT4 + if( accepted ) + { + _dee->acceptProposedAction(); + } +#else + _dee->accept( accepted ); +#endif + +} + + + + +QString stringPairDrag::decodeKey( QDropEvent * _de ) +{ +#ifdef QT4 + return( QString( _de->mimeData()->data() ).section( ':', 0, 0 ) ); +#else + return( QString( _de->encodedData( "lmms/stringpair" ) ).section( + ':', 0, 0 ) ); +#endif +} + + + + +QString stringPairDrag::decodeValue( QDropEvent * _de ) +{ +#ifdef QT4 + return( QString( _de->mimeData()->data() ).section( ':', 1, 1 ) ); +#else + return( QString( _de->encodedData( "lmms/stringpair" ) ).section( + ':', 1, 1 ) ); +#endif +} + diff --git a/src/widgets/pixmap_button.cpp b/src/widgets/pixmap_button.cpp index f2a6e9abc..11c604607 100644 --- a/src/widgets/pixmap_button.cpp +++ b/src/widgets/pixmap_button.cpp @@ -29,6 +29,7 @@ #include #include + #else #include @@ -87,9 +88,9 @@ void pixmapButton::paintEvent( QPaintEvent * ) } #ifdef QT4 - if( isChecked() ) + if( isChecked() || isDown() ) #else - if( isOn() ) + if( isOn() || isDown() ) #endif { if( m_activePixmap != NULL )