From 462c48d012c84bfaaeb97e65d3b35f3b1005eeb9 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Mon, 27 Mar 2006 12:19:04 +0000 Subject: [PATCH] bugfixes, new plugin "Vibed" and more git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@111 0778d3d1-df1d-0410-868b-ea421aaaa00d --- ChangeLog | 48 ++ TODO | 4 +- configure.in | 5 +- .../TripleOscillator/AnalogTimes2.cs.xml | 30 + include/instrument_track.h | 3 + include/note_play_handle.h | 2 +- include/preset_preview_play_handle.h | 2 +- include/project_journal.h | 8 +- include/track.h | 19 +- include/track_container.h | 7 + plugins/Makefile.am | 2 +- plugins/midi_import/midi_import.cpp | 2 +- plugins/organic/organic.cpp | 2 +- plugins/organic/randomise_pressed.png | Bin 0 -> 1077 bytes plugins/vibed/Makefile.am | 44 ++ plugins/vibed/artwork.png | Bin 0 -> 13354 bytes plugins/vibed/button_-1_off.png | Bin 0 -> 403 bytes plugins/vibed/button_-1_on.png | Bin 0 -> 372 bytes plugins/vibed/button_-2_off.png | Bin 0 -> 475 bytes plugins/vibed/button_-2_on.png | Bin 0 -> 452 bytes plugins/vibed/button_1_off.png | Bin 0 -> 392 bytes plugins/vibed/button_1_on.png | Bin 0 -> 391 bytes plugins/vibed/button_2_off.png | Bin 0 -> 476 bytes plugins/vibed/button_2_on.png | Bin 0 -> 481 bytes plugins/vibed/button_3_off.png | Bin 0 -> 472 bytes plugins/vibed/button_3_on.png | Bin 0 -> 477 bytes plugins/vibed/button_4_off.png | Bin 0 -> 448 bytes plugins/vibed/button_4_on.png | Bin 0 -> 432 bytes plugins/vibed/button_5_off.png | Bin 0 -> 465 bytes plugins/vibed/button_5_on.png | Bin 0 -> 451 bytes plugins/vibed/button_6_off.png | Bin 0 -> 489 bytes plugins/vibed/button_6_on.png | Bin 0 -> 483 bytes plugins/vibed/button_7_off.png | Bin 0 -> 417 bytes plugins/vibed/button_7_on.png | Bin 0 -> 408 bytes plugins/vibed/button_8_off.png | Bin 0 -> 482 bytes plugins/vibed/button_8_on.png | Bin 0 -> 481 bytes plugins/vibed/button_9_off.png | Bin 0 -> 503 bytes plugins/vibed/button_9_on.png | Bin 0 -> 498 bytes plugins/vibed/button_down.png | Bin 0 -> 250 bytes plugins/vibed/button_f_off.png | Bin 0 -> 445 bytes plugins/vibed/button_f_on.png | Bin 0 -> 435 bytes plugins/vibed/button_up.png | Bin 0 -> 270 bytes plugins/vibed/graph.cpp | 265 +++++++ plugins/vibed/graph.h | 87 ++ plugins/vibed/impulse_editor.cpp | 492 ++++++++++++ plugins/vibed/impulse_editor.h | 99 +++ plugins/vibed/logo.png | Bin 0 -> 5211 bytes plugins/vibed/nine_button_selector.cpp | 318 ++++++++ plugins/vibed/nine_button_selector.h | 89 +++ plugins/vibed/normalize_active.png | Bin 0 -> 469 bytes plugins/vibed/normalize_inactive.png | Bin 0 -> 477 bytes plugins/vibed/smooth_active.png | Bin 0 -> 487 bytes plugins/vibed/smooth_inactive.png | Bin 0 -> 523 bytes plugins/vibed/string_container.cpp | 95 +++ plugins/vibed/string_container.h | 83 ++ plugins/vibed/vibed.cpp | 747 ++++++++++++++++++ plugins/vibed/vibed.h | 100 +++ plugins/vibed/vibrating_string.cpp | 158 ++++ plugins/vibed/vibrating_string.h | 272 +++++++ plugins/vibed/wavegraph4.png | Bin 0 -> 10636 bytes src/core/arp_and_chords_tab_widget.cpp | 21 +- src/core/import_filter.cpp | 7 + src/core/note_play_handle.cpp | 2 +- src/core/preset_preview_play_handle.cpp | 31 +- src/core/song_editor.cpp | 3 +- src/core/track.cpp | 93 ++- src/core/track_container.cpp | 66 ++ src/lib/journalling_object.cpp | 13 +- src/lib/mmp.cpp | 7 +- src/lib/project_journal.cpp | 22 +- src/tracks/bb_track.cpp | 6 +- src/tracks/instrument_track.cpp | 4 +- src/tracks/pattern.cpp | 2 +- 73 files changed, 3180 insertions(+), 80 deletions(-) create mode 100644 data/presets/TripleOscillator/AnalogTimes2.cs.xml create mode 100644 plugins/organic/randomise_pressed.png create mode 100644 plugins/vibed/Makefile.am create mode 100644 plugins/vibed/artwork.png create mode 100644 plugins/vibed/button_-1_off.png create mode 100644 plugins/vibed/button_-1_on.png create mode 100644 plugins/vibed/button_-2_off.png create mode 100644 plugins/vibed/button_-2_on.png create mode 100644 plugins/vibed/button_1_off.png create mode 100644 plugins/vibed/button_1_on.png create mode 100644 plugins/vibed/button_2_off.png create mode 100644 plugins/vibed/button_2_on.png create mode 100644 plugins/vibed/button_3_off.png create mode 100644 plugins/vibed/button_3_on.png create mode 100644 plugins/vibed/button_4_off.png create mode 100644 plugins/vibed/button_4_on.png create mode 100644 plugins/vibed/button_5_off.png create mode 100644 plugins/vibed/button_5_on.png create mode 100644 plugins/vibed/button_6_off.png create mode 100644 plugins/vibed/button_6_on.png create mode 100644 plugins/vibed/button_7_off.png create mode 100644 plugins/vibed/button_7_on.png create mode 100644 plugins/vibed/button_8_off.png create mode 100644 plugins/vibed/button_8_on.png create mode 100644 plugins/vibed/button_9_off.png create mode 100644 plugins/vibed/button_9_on.png create mode 100644 plugins/vibed/button_down.png create mode 100644 plugins/vibed/button_f_off.png create mode 100644 plugins/vibed/button_f_on.png create mode 100644 plugins/vibed/button_up.png create mode 100644 plugins/vibed/graph.cpp create mode 100644 plugins/vibed/graph.h create mode 100644 plugins/vibed/impulse_editor.cpp create mode 100644 plugins/vibed/impulse_editor.h create mode 100644 plugins/vibed/logo.png create mode 100644 plugins/vibed/nine_button_selector.cpp create mode 100644 plugins/vibed/nine_button_selector.h create mode 100644 plugins/vibed/normalize_active.png create mode 100644 plugins/vibed/normalize_inactive.png create mode 100644 plugins/vibed/smooth_active.png create mode 100644 plugins/vibed/smooth_inactive.png create mode 100644 plugins/vibed/string_container.cpp create mode 100644 plugins/vibed/string_container.h create mode 100644 plugins/vibed/vibed.cpp create mode 100644 plugins/vibed/vibed.h create mode 100644 plugins/vibed/vibrating_string.cpp create mode 100644 plugins/vibed/vibrating_string.h create mode 100644 plugins/vibed/wavegraph4.png diff --git a/ChangeLog b/ChangeLog index 0bc988369..ea6a3d1c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,53 @@ +2005-03-26 Danny McRae + + * plugins/vibed/: + added "Vibed"-plugin, a powerful combination of PluckedStringSynth and + BitInvader that's capable of producing a surprisingly wide range of + sounds + +2006-03-26 Tobias Doerffel + + * src/lib/journalling_object.cpp: + in journallingObject::saveState(): append new dom-element to parent + before calling saveSettings() as some implementations of it depend on + knowing something about it's parent (e.g. whether it's the clipboard + etc.) - fixes several bugs related to clipboard-usage and drag'n'drop + +2006-03-25 Tobias Doerffel + + * include/instrument_track.h: + * src/core/preset_preview_play_handle.cpp: + disable journalling for all objects involved in preset-preview + + * src/tracks/instrument_track.cpp: + when saving preset, create new node below content-node of project, as + the behaviour of saveTrackSpecificSettings() was changed some days + before + + * src/lib/mmp.cpp: + bugfixes concerning project type-naming + + * src/core/arp_and_chords_tab_widget.cpp: + bugfixes concerning loading/saving settings + +2006-03-24 Tobias Doerffel + + * src/core/track.cpp: + in trackContentWidget::undoStep(): cast journalling object to + track-content-object and close it instead of deleting it - fixes crash + after undo of TCO-add + 2006-03-23 Tobias Doerffel + * plugins/organic/organic.cpp: + * plugins/organic/randomise_pressed.png: + added pixmap for visual feedback when pressing randomise-button + + * plugins/midi_import/midi_import.cpp: + removed attribute FASTCALL from midiImport::tryImport() for not + crashing LMMS, as tryImport() is not defined as FASTCALL in + importFilter-API + * src/core/export_project_dialog.cpp: fixed bug causing LMMS to crash when trying to export a project diff --git a/TODO b/TODO index 7bf82ef55..c234681b1 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,5 @@ +- when recording MIDI-events, add switch to disable recording of velocity +- integrated sample-browser in context-menu of sample-track/-tco - font-size-scaling-coefficient in setup-dialog - make note able of journalling - before calling undoStep/redoStep from journallingObject, save journalling-state-context and disabled journalling, restore afterwards @@ -5,7 +7,6 @@ - undo/redo-support in note/track etc. - save tco-settings in trackContentWidget::saveSettings() etc. instead of track::... - restore stacking-order of windows when loading project -- fix MIDI-import-filter - bristol-bindings - resample sample-track-tcos when using hq-mode - add support for panes-interface (like blender) (instead of MDI etc.) @@ -25,7 +26,6 @@ - level-meters in output-graph and channel-track - do not skip samples because of rounding-errors when resampling in src/lib/sample_buffer.cpp - MIDI-program/MIDI-mapping/process program-/channel-change-events from MIDI-files -- add note-len- and note-alignment-selectbox to piano-roll - DSSI-support - somehow avoid hidden plugin-descriptor-widgets plugin-browser if height of window is too small -> add scrollbar - use drawLineF() for drawing notes in pattern::paintEvent() in qt4-version diff --git a/configure.in b/configure.in index f06381aa3..db9c10e2d 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.4-cvs20060323, tobydox/at/users/dot/sourceforge/dot/net) -AM_INIT_AUTOMAKE(lmms, 0.1.4-cvs20060323) +AC_INIT(lmms, 0.1.4-cvs20060326, tobydox/at/users/dot/sourceforge/dot/net) +AM_INIT_AUTOMAKE(lmms, 0.1.4-cvs20060326) AM_CONFIG_HEADER(config.h) @@ -470,6 +470,7 @@ AC_CONFIG_FILES([Makefile plugins/plucked_string_synth/Makefile plugins/triple_oscillator/Makefile plugins/vestige/Makefile + plugins/vibed/Makefile lmms.spec]) AC_OUTPUT diff --git a/data/presets/TripleOscillator/AnalogTimes2.cs.xml b/data/presets/TripleOscillator/AnalogTimes2.cs.xml new file mode 100644 index 000000000..744848728 --- /dev/null +++ b/data/presets/TripleOscillator/AnalogTimes2.cs.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/instrument_track.h b/include/instrument_track.h index fd8803214..c3b73bb06 100755 --- a/include/instrument_track.h +++ b/include/instrument_track.h @@ -155,6 +155,9 @@ public: virtual void FASTCALL loadTrackSpecificSettings( const QDomElement & _this ); + using track::setJournalling; + + // load instrument whose name matches given one instrument * FASTCALL loadInstrument( const QString & _instrument_name ); diff --git a/include/note_play_handle.h b/include/note_play_handle.h index 7ab6a2a37..ca58047e2 100644 --- a/include/note_play_handle.h +++ b/include/note_play_handle.h @@ -160,7 +160,7 @@ public: int index( void ) const; // note-play-handles belonging to given channel - static constNotePlayHandleVector nphsOfChannelTrack( + static constNotePlayHandleVector nphsOfInstrumentTrack( const instrumentTrack * _ct ); // return whether given note-play-handle is equal to *this diff --git a/include/preset_preview_play_handle.h b/include/preset_preview_play_handle.h index d0395738d..c3d84ebba 100644 --- a/include/preset_preview_play_handle.h +++ b/include/preset_preview_play_handle.h @@ -60,7 +60,7 @@ public: virtual bool done( void ) const; static void cleanUp( engine * _engine ); - static constNotePlayHandleVector nphsOfChannelTrack( + static constNotePlayHandleVector nphsOfInstrumentTrack( const instrumentTrack * _ct ); private: diff --git a/include/project_journal.h b/include/project_journal.h index 1ac494f23..50731fa20 100755 --- a/include/project_journal.h +++ b/include/project_journal.h @@ -90,7 +90,13 @@ public: // journalling information about the ID get's lost void forgetAboutID( const jo_id_t _id ); - void clear( void ); + void clearJournal( void ) + { + m_journalEntries.clear(); + m_currentJournalEntry = m_journalEntries.end(); + } + + void clearInvalidJournallingObjects( void ); journallingObject * getJournallingObject( const jo_id_t _id ) { diff --git a/include/track.h b/include/track.h index eb555012a..5c710f690 100644 --- a/include/track.h +++ b/include/track.h @@ -129,8 +129,8 @@ protected: void setAutoResizeEnabled( bool _e = FALSE ); float pixelsPerTact( void ); - virtual void undoStep( journalEntry & _edit_step ); - virtual void redoStep( journalEntry & _edit_step ); + virtual void undoStep( journalEntry & _je ); + virtual void redoStep( journalEntry & _je ); protected slots: @@ -210,8 +210,8 @@ protected: return( "trackcontentwidget" ); } - virtual void undoStep( journalEntry & _edit_step ); - virtual void redoStep( journalEntry & _edit_step ); + virtual void undoStep( journalEntry & _je ); + virtual void redoStep( journalEntry & _je ); private: @@ -277,7 +277,7 @@ private: // actual widget shown in trackContainer -class trackWidget : public QWidget +class trackWidget : public QWidget, public journallingObject { Q_OBJECT public: @@ -338,6 +338,15 @@ public slots: protected: + virtual void undoStep( journalEntry & _je ); + virtual void redoStep( journalEntry & _je ); + + virtual QString nodeName( void ) const + { + return( "trackwidget" ); + } + + virtual void dragEnterEvent( QDragEnterEvent * _dee ); virtual void dropEvent( QDropEvent * _de ); virtual void mousePressEvent( QMouseEvent * _me ); diff --git a/include/track_container.h b/include/track_container.h index ee1f10e65..6a0891c6a 100644 --- a/include/track_container.h +++ b/include/track_container.h @@ -129,6 +129,9 @@ public: protected: + virtual void undoStep( journalEntry & _je ); + virtual void redoStep( journalEntry & _je ); + virtual void dragEnterEvent( QDragEnterEvent * _dee ); virtual void dropEvent( QDropEvent * _de ); virtual void mousePressEvent( QMouseEvent * _me ); @@ -152,6 +155,10 @@ protected slots: private: + enum actions + { + ADD_TRACK, REMOVE_TRACK + } ; class scrollArea : public QScrollArea { diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 38b13efb8..50936ae95 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -2,5 +2,5 @@ if VST_SUPPORT VESTIGE_SUBDIR=vestige endif -SUBDIRS = audio_file_processor bit_invader midi_import organic plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR) +SUBDIRS = audio_file_processor bit_invader midi_import organic plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR) vibed diff --git a/plugins/midi_import/midi_import.cpp b/plugins/midi_import/midi_import.cpp index 85eb91f15..7fc172b77 100644 --- a/plugins/midi_import/midi_import.cpp +++ b/plugins/midi_import/midi_import.cpp @@ -85,7 +85,7 @@ midiImport::~midiImport() -bool FASTCALL midiImport::tryImport( trackContainer * _tc ) +bool midiImport::tryImport( trackContainer * _tc ) { if( openFile() == FALSE ) { diff --git a/plugins/organic/organic.cpp b/plugins/organic/organic.cpp index 7e02726ae..d58dabdf1 100644 --- a/plugins/organic/organic.cpp +++ b/plugins/organic/organic.cpp @@ -184,7 +184,7 @@ organicInstrument::organicInstrument( instrumentTrack * _channel_track ) : m_randBtn = new pixmapButton( this, eng() ); m_randBtn->move( 100, 200 ); m_randBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "randomise" ) ); + "randomise_pressed" ) ); m_randBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "randomise" ) ); //m_randBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). diff --git a/plugins/organic/randomise_pressed.png b/plugins/organic/randomise_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..e3a7470d593e5d97418669ca93b582aed3fcb7f0 GIT binary patch literal 1077 zcmV-51j_q~P)_C zX>@2HRA^-&M@dak?_?!z000B5NklbnqNp9{L#e5qPlg@I2D903yd?$>@mXNe}ShOMM^htvyX{{P^ql=TBYuPmusXKnO0J{UFQzD+>;f zZSdsq|FY9!kz{Xq9*?vY(n48070dFaaKPc2q8Ss)kf1^^Nt5`YOXh&`UAo zO9~zODnl}zu(>B9u`t0GXcRR$tHj15`>b_69svXuGIdAODT<-Lwtilt)GdYmX)^U< z?eVo(cr6yD7}BIS8>)?2|Mv$j1Hiopb8}uN<}l)+Hba+2p-qz;KhI7^;vt4*mSU*T`tob- z=Mh4DgqrJ2fzToVPz)7{uD;&+=B9qwG>B zLRpdg`t5P0tWsJi?``R)87i>47*ED>`_JbQ|29kS^uCwni_5-W?%3Zt^Df4C)bU+G zUZGM}St(cl8TdV0z~>PNq3x%Op1^iq0S*HI`lkeK@p-%tAvD-I9Eq>3#X^7h@80#f zds_PVJpS7~mv*fFv`1W4T$)NJ0f3~*m4`v|k*->$E}2enn8O(FtQQhOd2yL*{wBtl z<2dL1Oiq^-$>+Q-j4{h`&iNTtS@rH`oo48-e){wUNq)V$@rd?lH1SYK2xY}(9-j+i zj4}T0-n89q-PQ9T5*#4uj4$Zbme)3Fnno;F#3D((x=|z$*=MaLy?JL#&+%7m?ujqQ zKfxHP%WJmi{dTwIj?aw%lyY@zV>`vryNo0t1WmQau1#I#^9X{^?=*G;KyOQ*-EE!o vx)4GNY57TG_qKz5{*U(z03AHH-y;1AcEpr1!9vib00000NkvXXu0mjf7K#L! literal 0 HcmV?d00001 diff --git a/plugins/vibed/Makefile.am b/plugins/vibed/Makefile.am new file mode 100644 index 000000000..d266d4810 --- /dev/null +++ b/plugins/vibed/Makefile.am @@ -0,0 +1,44 @@ +AUTOMAKE_OPTIONS = foreign 1.4 + + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I. + + +AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="vibedstrings" + + +%.moc: ./%.h + $(MOC) -o $@ $< + + +MOC_FILES = ./vibed.moc ./graph.moc ./impulse_editor.moc ./nine_button_selector.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= libvibedstrings.la + +libvibedstrings_la_SOURCES = vibed.cpp \ + vibed.h \ + graph.cpp \ + graph.h \ + vibrating_string.cpp \ + vibrating_string.h \ + string_container.cpp \ + string_container.h \ + impulse_editor.cpp \ + impulse_editor.h \ + nine_button_selector.cpp \ + nine_button_selector.h + +$(libvibedstrings_la_SOURCES): ./embedded_resources.h diff --git a/plugins/vibed/artwork.png b/plugins/vibed/artwork.png new file mode 100644 index 0000000000000000000000000000000000000000..1bd60dddb046fc9d9120dc07d5daa1b0a59f8412 GIT binary patch literal 13354 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 RzZd`j002ovPDHLkV1heX!SetB literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_-2_on.png b/plugins/vibed/button_-2_on.png new file mode 100644 index 0000000000000000000000000000000000000000..a5cb24de3f641cd786dedca3280f83ceff0e48c3 GIT binary patch literal 452 zcmV;#0XzPQP)_C zX>@2HRA^-&M@dak?_?!z0003yNkl`115lN z+k|0=Wmz)??RJ}5tu_`arBF)68lJN++~*!}6E0n=OT{UZ>o1Vc=f4~s#{s}F3;-e- zQD41f<7yp%$K@x^)@;fbJMpNEW;5nC%nG^NZlKOh0Ngj1*Ue6>&jhI7T*ri3YJ#Fa zse4NSh9f8ELSY5@+XBQ$kUmb1hh#MVen{#>{oLwb&{8uv@Ue~(m@Om5NdT`B(6a~h z>;c|hFd>6dMCw#wwha8O5G{4wF< z>&kwOnTN;7a^I@0&w)a+C9V-A&iT2ysd*&~&PAz-C8;S2<(VZJ3LzP(3hti10q;{( z^MDHfd%8G=Xq?|WalhB$0Fh($Ke@|SU+`G&FwO5SR}%YoEk^c}*-sdIR@aK}Om62B z5_!YCLZU}tf|_@lwPexC=8C{YhW{YAVDIwDKoQOYkH}&M z25w;xW@MN(M*=9wUgGKN%6^TRhmVQXmtFfWP)N4KHKN2hKQ}iuuY|$5C^fMpHASI3 zvm`?yBqLS9-P1SVeTr%xP~jU-7sn8d^Lr=l^GnWqs6xw0t%;% zdJK;g{!tE?rdm1gGQ)(Rbq?G=4_^Lg{P%P8dR9jUhe;~;#k&`Mc=r0_l;5Y>1xyPH zuYcRHwaoO@>6AyTwwLGZov-wK(!;Ma9%gJY-NX z&w7Ix@m0$Xm*`v#{44(JR0Hcz356{;xMpojy?MDV{+mfe$34EpH)YKi6;z~Jq7Ut~ gf3qUwSM~?)KTF+R91rWR1Nxi6)78&qol`;+0McHXSO5S3 literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_2_off.png b/plugins/vibed/button_2_off.png new file mode 100644 index 0000000000000000000000000000000000000000..558ea6b299f6a971d541cc58f89673f019643223 GIT binary patch literal 476 zcmV<20VDp2P)Sd0013yMObu0Z*6U5Zgc=ca%Ew3Wn>_C zX>@2HRA^-&M@dak?_?!z0003~Nkls;3l+~u7Y@X3c-b$Sv}*!`{8}w zhgV7@5*B|{E|)_Fh{a+I1_M-8#p!g?@At<-tyb$3R1^h8Q2-D^5cK)*dpszz%xk+% zsaC@*ZS4F$}}rECakW8n!VX z3i0st#KqMW0QaR5=~RkZy*?CK2B?&uZDYSuMv^2<(*z(IS)|?R49x(Dug6=KWkWm3 zB--`+{ zGLvC-X^BFyh!74E@i@2n{N#;(-!uR#n#PKzjeUd>aA7U_tG5&UQxahP2Yd$| literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_2_on.png b/plugins/vibed/button_2_on.png new file mode 100644 index 0000000000000000000000000000000000000000..0c5f0d13fadd29938eb2fc734983713f1f841e13 GIT binary patch literal 481 zcmV<70UrK|P)5XC%;QG^kW6U!ar{DJ1{~!`0F?<%N6N zR-4tA6x;q5u}%!FHHk!`=UA`T0kABKr;a?pb6EU<3A;FHqIf)|6_Gr*d7(NaI)VjtwiW0rBF_Q+-5`B9= zqP`!uQ8|r$XF&wo`H;8s=4eN~+yOvkH7fh<{kDx#>UVHDKQ**53iWr?vAXKInX$o7 Xt~_yLi0tl900000NkvXXu0mjf{lmZ0 literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_3_off.png b/plugins/vibed/button_3_off.png new file mode 100644 index 0000000000000000000000000000000000000000..83a815912ce03b3a64f184785edb11d7d2a7b8be GIT binary patch literal 472 zcmV;}0Vn>6P)_C zX>@2HRA^-&M@dak?_?!z0003`NklYr!`97S*vf*iC(CoQ!UgeW0|5)6k>?zo1?3en2%_}=%!d*8=1 zghC;me=40$BLMjQepFROmSrSKVl)~}g*u(i7buD%q9_6&2m&6LizS;1NfdeM_bJzE zyb6bCnugVC{qO;_+id_$CKIcQg3E5FT&eIn7~oM9*4=K-GZ{2Z8&4Jh?wZYUq1kG2 zSt#(_>jALraBv)rQg1YVtSkWBTvsQuta&_aZ*H;Y^Kp^SPk4;ejF#E{(X ztwlfzM@)3ed3?-!Gh+dUf0P4IsZ>x(;kxcfpxtg$tJV6TloBZ=0HGanQaI&0cSFbN zkbj${e7ixeH;vYsY&QEnvDIn;AcP=TxaVT#l45<4%zK8%LW|1$A)CkRXsrjW-UY!| zBMKsx&x)j8Qy3zq@>%NJ3L4GkfMp9XzVF4dC|{#iBEnULc(O_FC%-h$^Rb65K`lk} zN+Hpl!MPGKeJGeZl1!9c+=B$2-5w@o#sm8~EabU>B$!DPzvIvP*y&_C zX>@2HRA^-&M@dak?_?!z0003uNklN7k?;7gP^sGExiN5CCa#S z^1wsLXsD^6x#rr6hL)g~punTSd;`6Niq0GkE<6r=3ZmH{gvTXj-|_kK;ro0a9?7z- zF$>CZ98>_qFc=Pp2qDmQoxxx*6AFR=$8nGWG)+SY0e~#a07#O=RSSu7rr&0j;z7N1?H2U#XfRAoBvW}*z?AtbBzt2iG%e(8wR#pMtUSA@^ zMy7I?V;mjZH)% z!E@`0_Wc6@*XI|%cZ?(+9-t};%efrur4m)M!d2mA(B$yC<-QMv8_0000YhW{YAVDIwDKoQOYkH}&M z25w;xW@MN(M*=9wUgGKN%6^TRhmV=>@VUb#Kq1)@*N775{M_8syb=cIqSVBa)D(sC z%#sX+kc?CXcTeAd_bIA*3=E8-o-U3d8t3Ou+URvSfWg&&@*Wez2VyVyUreZLoZP*m zB#dSMp`!<{1|E$!;G0|WMVn_)Qf8~egocj3uuET_s`9zso-ixu{SUqGbIbMDGm89i zW@~u=J0-F$_ck|kp^PvKqf~>yBB3Czqc4wHwnw`&yx7Ip@OoEpl0=)T@PhsS&g}lo z=pf=c`ScVm`>pm8Q!;i=EZ$w*{x@y%7NL1ndw+j+vU6bE=atY58UsQJ2t6*5x(Xf8<#Xo(Ui}+?O zaK5KCVYcL^#Rlt-BrW>4YTmdKI;Vst08}Eb_W%F@ literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_5_off.png b/plugins/vibed/button_5_off.png new file mode 100644 index 0000000000000000000000000000000000000000..a37a54736f6612dd41ecac446f2d907b25aab500 GIT binary patch literal 465 zcmV;?0WSWDP)_C zX>@2HRA^-&M@dak?_?!z0003&A`qzv5z?i@;~K&%Gn4#|U*6}v z_kBD;*L9bFs!%B42Z%f%rczSuJa(=YhW{YAVDIwDKoQOYkH}&M z25w;xW@MN(M*=9wUgGKN%6^TRhmTq5quBcEKq1)@*N775{M_8syb=cIqSVBa)D(sC z%#sX+kc?CXcTeAd_bIA*3=E7Ko-U3d8t3OuGW0uaAmKJY+1l4jFgQ{`+#|1np_5tR zE7uzXgJR}{2F6a)j=9Dc78;Z+7m{=kbt=)|@r~|^HCABt3RwNQLO5glZIjt&^#ihduSqrd?L7SP*2yCUYqy>~_Sx!M)T*nmwj25eGc1|1 zM{h6VhSI$=o4fr*FXJ?k7yRSxd-Pc?72V0c6NZ|!PfQKN&095wGx7xFFp5y!yo zwp{kz^UJ>)Qnqa@H#<`O@xpeY@UosPw!0HH_a0oDw#O)KgMHGD&yD5p1?T+ISh`HQ rGJB8;4*l+`njxgN@xNAF66S% literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_6_off.png b/plugins/vibed/button_6_off.png new file mode 100644 index 0000000000000000000000000000000000000000..874c9531eddccd90472b9920fd60a4c4ddc2427e GIT binary patch literal 489 zcmV_C zX>@2HRA^-&M@dak?_?!z0004CNkl!#U3} z1pVh}7dbz8EeT=-pVLXm%x6|Ql`@LheP7(1t)9q$vCG@R|nu!3XsT8B*V+!9+ fqDh&6QZwKufi8NH_l{%700000NkvXXu0mjf#2UqB literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_6_on.png b/plugins/vibed/button_6_on.png new file mode 100644 index 0000000000000000000000000000000000000000..3ee7149288db6970d882e7d473e9a504c3c64dac GIT binary patch literal 483 zcmeAS@N?&q;$mQ6;PUiv2?El5Ak4uAB;`GHF9IpHByV>YhW{YAVDIwDKoQOYkH}&M z25w;xW@MN(M*=9wUgGKN%6^TRhmYBO&S`HOppa~dYeb22er|4RUI~M9QEFmIYKlU6 zW=V!ZNJgrHyQgo!`xMnY1_nkCPZ!4!jq`IS9rR)f6lvRUef_n`vc^L?${iCV!gZH~ z>R%Av@{+47LtOC6I`I|kA0(N&!*ZjhBwbT#%}Mlfba4%sTs8N$(*`!jjhp}cwEy>6 zzK?L+!7|$F0FZ`JQ6>n|-$A%qsWoF?$%QeKjlo#VWnlsX`xrseEqF)X80V z@lKHBn~LJtcieMTebp~2?#eCv9OSl#%O$!+;r!_@2lii{%e8>}U)5}d+y}x*zXPvS z-pJybbCyZPWt~d!X})ugQ`WCFbDQ~a!PPgO7Z-CJ5?^7=S;!G%e8W&B#^b}m`_C zX>@2HRA^-&M@dak?_?!z0003PNklD?1iMaut{l|(kobU1;JuXu@VwYLL`FISp;n3TFg333c(=mF40rYcb;L+VRD}5 zX?85%_ptz)%_hs`l0u<=^wOh8{4)4xN%)f!`Nt6O7YO^p_IaL9Do%R zLI7ZzCQ?d9lL_Cm8Cq-3Yc-r=5g`Ohsr6+Rz}I-ZKDceS`I*nrdNuk*tHtwh$meLZ z@d^vzk=&@2Cpw$Sth)yH|U2UaUB029+yg-Rjc%Z zeqx>qFY5~8IOb^(?gozz4|og$qQxRHx6YhW{YAVDIwDKoQOYkH}&M z25w;xW@MN(M*=9wUgGKN%6^TRhmVD?r$6*FP)N4KHKN2hKQ}iuuY|$5C^fMpHASI3 zvm`?yBqLS9-P1SVeTr%xP~l%s7sn8d^K&O{^g7}o(6;~1yDmmimS(fEMKhc~ux|OV za?1u`Zf*I4HeDGD1&#>w^GB}UlBCr#q%!Nxw-*de^=hDyQx$a%lM%3 z@TYBalGnPr%vx>dt9HNj?qu0ByAOu)HT*G1&)jn2amAf|9}`RNSN5-|?%K+4@tw<8 zhF|hes>@FOfQEh9r>h*=cLuVg8rZ%Fx2@ak6u_C zX>@2HRA^-&M@dak?_?!z00045NklIXOp zMuFTRsG$}=mc%kBFd6Ez%mKRGalZDb9gyA zNs=`FDOr{=0{H!Y#^W(2lL=828I4ANLW-h%gMuI+2m$~rqKMn+WX);?O+y(Dd2O|r zXd0@jVzF2NzQAs`3xL63K=S!mHJf=X7SRBY%f*Jn!F8d4s;bjuBS5R&o*HMtAXk|T z-ChrXC!38#G)leEn5k?8c&}EbMy=Uo-EQaZ;U0i(ua|10K65h#e=3zuBj`2$nOG#U7~FDu$mVmr)oN7gb+Y*!n{Lk>I9IjV z>5w|VK)$^JK-$@*(QYkHJh@EJ{}>Pog*gs}Q2KpNlgY)2gW-@!Jic&tdX|(9(3Sx| Y0r6IPuk#a(hX4Qo07*qoM6N<$f(v@S&j0`b literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_8_on.png b/plugins/vibed/button_8_on.png new file mode 100644 index 0000000000000000000000000000000000000000..370ad8208675ec3118cb62b5b65614a57c0f3e73 GIT binary patch literal 481 zcmV<70UrK|P)+qO|kVVdS#pwsD4tJOl#FboXC0H7y(T&-4cQjdT} z_QN9ow8zpgNe~32QmLQBcDo9IuIpTH-_VVB*{tS38{(|FlviwaZ+8fSV6s)W*&G=! z2OZWgvgpqOfOLA9deNcbIMXxMAMQtna5dbtOYAOe-P`IT9<_-#mX!&?ahc~4J}*7| zeH9u5NFK+gmLz@~UcpCJ1&Na=iDDF46LctDAer4g>KcdG7E#> X3Oi>bv12js00000NkvXXu0mjff1ko6 literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_9_off.png b/plugins/vibed/button_9_off.png new file mode 100644 index 0000000000000000000000000000000000000000..2c71abff8218e5223390b86141e957f260f96ce4 GIT binary patch literal 503 zcmV_C zX>@2HRA^-&M@dak?_?!z0004QNklr{R0IzY!M5h zCWmshaw=*loFr(7h~B1X%%MSOb8&2HY$yuKtOlhd#9L5dFJ3Xiw;BRN?S(w!;rHP= z=kVw}9?v`ftZ+Dt9>DE(Q!ExS8jTnX2J-p*k4RP3FDOY8k|Y5j2m&p#jI+BNlPr_T zW;wdJK+EMQl}gxbHh@op%qCM+PWbL}b4yDoon35i26%jaqFgTXqGkSuNj1gD)FeHF z1Eg+l0odC=sLJSTktm7`yIh!LnSN(4eGUhKV34Gm`W-emH8C?jK}UN#*U2RFYpd++ t?$%9J2Q!++(Aemo-%g;x(gE*{zz;F@d(24!BYFS;002ovPDHLkV1iQJ%5(q# literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_9_on.png b/plugins/vibed/button_9_on.png new file mode 100644 index 0000000000000000000000000000000000000000..629d9996469149a4d834fef0c30293cd50355612 GIT binary patch literal 498 zcmV3b0d<;I3ik(po zmKm##vUamVv^I(Bx8Yl|4v6QM<>VYqn!q zF|^L+#j`*w3Y>TYIqOo}`2awL+lSu@5e)A7kuxsu2X(}Y01re(bbm)@=(a{EZlX{) z+l^*nTK^j=P0?6(Q9*@VaFO#K{v!k3)_TAo)VCUV;|lFTVD1WFoa^{}KBSbtL#-kR oZFX< z>&kwOnTN-W>vvI07*I&I#5JPCIX^cyHLrxhxhOTUBsE2$JhLQ2AtWPJ!QIn0;C+f} z9#CPSr;B5V#`(Jw4f&WAd03t|#eQJ0V_g5t{>#p$zWf`zv=^y(6$@&FF5BvM?`qzG zgG@{T*+7e6OAVZU>{gW~JAu rodwAg>qT5sd`&jrcbWQJZ}XgaA~F)`dU5hV%Naaf{an^LB{Ts5EE!bK literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_f_off.png b/plugins/vibed/button_f_off.png new file mode 100644 index 0000000000000000000000000000000000000000..203cd8aedb4692c64b047a46e29a04cdf19cda49 GIT binary patch literal 445 zcmV;u0Yd(XP))^0mGI0013yMObu0Z*6U5Zgc=ca%Ew3Wn>_C zX>@2HRA^-&M@dak?_?!z0003rNkl!6+%6aVy0ckkZs?s0dD zWm!}Hsd~MR22iO~2!a5^Fwk|K(P$J2`M&=N3Ly|euxy&FW-_D_2?oO<yk_+0p7rVzYl=tdAPkEd(|p8w#{TRK~+^Y@_Ed7T;?R$ab0Po-gkU#w^`72 z*0Nb{ZJS-on#pMZ53Qy&R?=xcyq$8HrC1Edx#Q(|$iVkyPK~;Ri<271`v-FV6_O{0 z>GbN7^<0ka(pKoY_S1Vkb-M^HJo2roq9}441OfN0*6(1kP@r~r1i0013yMObu0Z*6U5Zgc=ca%Ew3Wn>_C zX>@2HRA^-&M@dak?_?!z0003hNklJUtkHk5j{d+s^>=Rfxvz<_^1 z0C=8fl z6h#0?ORyDg5FSQsUz9O00Jw7(X%$+jE;T;X>nYJ$=m1cw-J^4w&y_ZF=LOymKK|$g zKyZ7L5_&1-m+Ms&u^p4Y&Y@ppf@Y#~-4bS23127QbdP%J*=m}jt&YR&*$iq`qjq%m zb7a8^O_1a7Mx!Q0GGKtA3`Af}Hug6)-Q#4h&S{T+c^Fd&ksVc5Eo6241f|r3sMGva d*DXzL`~l5EW?*_-@ml}@002ovPDHLkV1ld#s?-1g literal 0 HcmV?d00001 diff --git a/plugins/vibed/button_up.png b/plugins/vibed/button_up.png new file mode 100644 index 0000000000000000000000000000000000000000..0a517f508d11f4dbaca19e1d9bb1b5066eed775f GIT binary patch literal 270 zcmeAS@N?&q;$mQ6;PUiv2?El5Ak4uAB;`GHF9Ipf0*}aI1_o|n5N2eUHAey{$X?>< z>&kwOnTJPPAYGzmGEhji#5JPCIX^cyHLrxhxhOTUBsE2$JhLQ2AtWPJ!QIn0;C+f} z9#CPcr;B5V#`(MFH*y_T5NLgPKVgDI!`h6QlTs&{6gocF6=)BRD4KJkv*~n9>7~o% zRpv(|#I4kq9^nvhT5zqam@iv*>6HGAdC%2NjwSRkI%t-1Y`NCKaj&{T^x2&41@>#V zPIp$?^j7&m?X0T%F%REXy=;3G{Uh#g`i}oAx#z9>rCz`=&G-W&Kaa{rlcmS%fDU5t MboFyt=akR{0H(8GzW@LL literal 0 HcmV?d00001 diff --git a/plugins/vibed/graph.cpp b/plugins/vibed/graph.cpp new file mode 100644 index 000000000..f310ae426 --- /dev/null +++ b/plugins/vibed/graph.cpp @@ -0,0 +1,265 @@ +/* + * graph.cpp - a QT widget for displaying and manipulating waveforms + * + * Copyright (c) 2006 Andreas Brandmaier + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +#include + +#else + +#include +#include +#include + +#endif + + +#include "graph.h" +#include "string_pair_drag.h" +#include "sample_buffer.h" +#include +#include + +using namespace std; + + + +graph::graph( QWidget * _parent, engine * _engine ) : + QWidget( _parent ), + engineObject( _engine ) +{ + m_mouseDown = false; + + setFixedSize( 132, 104 ); + + setAcceptDrops( TRUE ); + +#ifndef QT4 + setBackgroundMode( NoBackground ); +#endif + +} + + + + +graph::~graph() +{ +} + +void graph::setForeground( const QPixmap &_pixmap ) +{ + m_foreground = _pixmap; +} + +void graph::setSamplePointer( float * _pointer, int _length ) +{ + samplePointer = _pointer; + sampleLength = _length; + update(); +} + +void graph::loadSampleFromFile( const QString & _filename ) +{ + // zero sample_shape + for (int i = 0; i < sampleLength; i++) + { + samplePointer[i] = 0; + } + + // load user shape + sampleBuffer buffer( eng(), _filename ); + + // copy buffer data + sampleLength = min( sampleLength, static_cast(buffer.frames()) ); + for ( int i = 0; i < sampleLength; i++ ) + { + samplePointer[i] = (float)*buffer.data()[i]; + } + +} + +void graph::mouseMoveEvent ( QMouseEvent * _me ) +{ + // get position + int x = _me->x(); + int y = _me->y(); + + + // avoid mouse leaps + int diff = x - m_lastCursorX; + + if( diff >= 1 ) + { + x = m_lastCursorX + 1; + } + else if( diff <= 1 ) + { + x = m_lastCursorX - 1; + } + else + { + x = m_lastCursorX; + } + + changeSampleAt( x, y ); + + // update mouse + m_lastCursorX = x; + +} + +void graph::mousePressEvent( QMouseEvent * _me ) +{ + if( _me->button() == Qt::LeftButton ) + { + // toggle mouse state + m_mouseDown = true; + + // get position + int x = _me->x(); + int y = _me->y(); + + changeSampleAt( x,y ); + + // toggle mouse state + m_mouseDown = true; +#ifndef QT3 + setCursor( Qt::BlankCursor ); +#else + setCursor( QCursor::BlankCursor ); +#endif + m_lastCursorX = x; + } +} + +void graph::changeSampleAt(int _x, int _y) +{ + // consider border of background image + _x -= 2; + _y -= 2; + + // boundary check + if (_x < 0) { return; } + if (_x > sampleLength) { return; } + if (_y < 0) { return; } + if (_y >= 100) { return; } + _y = 100 - _y; + + // change sample shape + samplePointer[_x] = (_y-50.0)/50.0; + emit sampleChanged(); + + +} + +void graph::mouseReleaseEvent( QMouseEvent * _me ) +{ + if( _me->button() == Qt::LeftButton ) + { + // toggle mouse state + m_mouseDown = false; +#ifndef QT3 + setCursor( Qt::ArrowCursor ); +#else + setCursor( QCursor::ArrowCursor ); +#endif + update(); + } +} + + + +void graph::paintEvent( QPaintEvent * ) +{ + +#ifdef QT4 + QPainter p( this ); +#else + QPixmap draw_pm( rect().size() ); + draw_pm.fill( this, rect().topLeft() ); + + QPainter p( &draw_pm, this ); +#endif + + p.setPen( QColor( 0xFF, 0xAA, 0x00 ) ); + + p.drawLine( 1+sampleLength, 2, 1+sampleLength, 102); + + float xscale = 128.0 / sampleLength; + + for (int i=0; i < sampleLength-1; i++) + { + p.drawLine(2+static_cast(i*xscale), + 2+static_cast(-samplePointer[i]*50) + 50, + 2+static_cast((i+1)*xscale), + 2+static_cast(-samplePointer[i+1]*50 + 50) + ); + } + + // draw Pointer + if (m_mouseDown) { + QPoint cursor = mapFromGlobal( QCursor::pos() ); + p.setPen( QColor( 0xAA, 0xFF, 0x00 ) ); + p.drawLine( 2, cursor.y(), 130, cursor.y() ); + p.drawLine( cursor.x(), 2, cursor.x(), 102 ); + } + p.drawPixmap( 0, 0, m_foreground ); + +#ifndef QT4 + // and blit all the drawn stuff on the screen... + bitBlt( this, rect().topLeft(), &draw_pm ); +#endif + +} + + +void graph::dropEvent( QDropEvent * _de ) +{ + QString type = stringPairDrag::decodeKey( _de ); + QString value = stringPairDrag::decodeValue( _de ); + + if( type == "samplefile" ) + { + loadSampleFromFile( value ); + _de->accept(); + } +} + +void graph::dragEnterEvent( QDragEnterEvent * _dee ) +{ + if( stringPairDrag::processDragEnterEvent( _dee, + QString( "samplefile" ) ) == FALSE ) + { + _dee->ignore(); + } +} + + +#include "graph.moc" diff --git a/plugins/vibed/graph.h b/plugins/vibed/graph.h new file mode 100644 index 000000000..6976c3452 --- /dev/null +++ b/plugins/vibed/graph.h @@ -0,0 +1,87 @@ +/* + * graph.h - a QT widget for displaying and manipulating waveforms + * + * Copyright (c) 2006 Andreas Brandmaier + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _GRAPH_H +#define _GRAPH_H + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +#include + +#else + +#include +#include +#include + +#endif + + +#include "engine.h" + + +class graph : public QWidget, public engineObject +{ + Q_OBJECT +public: + graph( QWidget * _parent, engine * _engine ); + virtual ~graph(); + + void setSamplePointer( float * pointer, int length ); + void setForeground( const QPixmap & _pixmap ); + void loadSampleFromFile( const QString & _filename ); + +signals: + void sampleSizeChanged( float f ); + void sampleChanged( void ); + +protected: + virtual void paintEvent( QPaintEvent * _pe ); + virtual void dropEvent( QDropEvent * _de ); + virtual void dragEnterEvent( QDragEnterEvent * _dee ); + virtual void mousePressEvent( QMouseEvent * _me ); + virtual void mouseMoveEvent( QMouseEvent * _me ); + virtual void mouseReleaseEvent( QMouseEvent * _me ); + +private: + + void changeSampleAt(int _x, int _y); + + QPixmap m_foreground; + + + float *samplePointer; + int sampleLength; + + bool m_mouseDown; + int m_lastCursorX; + +} ; + +#endif diff --git a/plugins/vibed/impulse_editor.cpp b/plugins/vibed/impulse_editor.cpp new file mode 100644 index 000000000..fa172b5ae --- /dev/null +++ b/plugins/vibed/impulse_editor.cpp @@ -0,0 +1,492 @@ +/* + * impulse_editor.cpp - graphic waveform editor + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 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 +#include +#include + +#endif + +#include "impulse_editor.h" +#include "vibed.h" +#include "tooltip.h" +#include "oscillator.h" +#include "song_editor.h" + + +impulseEditor::impulseEditor( QWidget * _parent, int _x, int _y, + engine * _engine, Uint32 _len ) : + QWidget( _parent, "impulseEditor" ), + engineObject( _engine ), + m_sampleLength( _len ), + m_normalizeFactor( 1.0f ), + m_forward( TRUE ) +{ + setFixedSize( 153, 124 ); + m_base = QPixmap::grabWidget( _parent, _x, _y ); + setPaletteBackgroundPixmap( m_base ); + + m_graph = new graph( this, eng() ); + m_graph->setForeground( PLUGIN_NAME::getIconPixmap( "wavegraph4" ) ); + m_graph->move( 0, 0 ); + m_graph->setCursor( QCursor( Qt::CrossCursor ) ); + toolTip::add( m_graph, tr ( "Draw your own waveform here " + "by dragging your mouse onto this graph" ) ); + + connect( m_graph, SIGNAL ( sampleChanged( void ) ), + this, SLOT ( sampleChanged( void ) ) ); + + m_sinWaveBtn = new pixmapButton( this, eng() ); + m_sinWaveBtn->move( 136, 3 ); + m_sinWaveBtn->setActiveGraphic( embed::getIconPixmap( + "sin_wave_active" ) ); + m_sinWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "sin_wave_inactive" ) ); + m_sinWaveBtn->setChecked( TRUE ); + toolTip::add( m_sinWaveBtn, + tr( "Click here if you want a sine-wave for " + "current oscillator." ) ); + connect( m_sinWaveBtn, SIGNAL (clicked ( void ) ), + this, SLOT ( sinWaveClicked( void ) ) ); + + + m_triangleWaveBtn = new pixmapButton( this, eng() ); + m_triangleWaveBtn->move( 136, 20 ); + m_triangleWaveBtn->setActiveGraphic( + embed::getIconPixmap( "triangle_wave_active" ) ); + m_triangleWaveBtn->setInactiveGraphic( + embed::getIconPixmap( "triangle_wave_inactive" ) ); + toolTip::add( m_triangleWaveBtn, + tr( "Click here if you want a triangle-wave " + "for current oscillator." ) ); + connect( m_triangleWaveBtn, SIGNAL ( clicked ( void ) ), + this, SLOT ( triangleWaveClicked( void ) ) ); + + + m_sawWaveBtn = new pixmapButton( this, eng() ); + m_sawWaveBtn->move( 136, 37 ); + m_sawWaveBtn->setActiveGraphic( embed::getIconPixmap( + "saw_wave_active" ) ); + m_sawWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "saw_wave_inactive" ) ); + toolTip::add( m_sawWaveBtn, + tr( "Click here if you want a saw-wave for " + "current oscillator." ) ); + connect( m_sawWaveBtn, SIGNAL (clicked ( void ) ), + this, SLOT ( sawWaveClicked( void ) ) ); + + + m_sqrWaveBtn = new pixmapButton( this, eng() ); + m_sqrWaveBtn->move( 136, 54 ); + m_sqrWaveBtn->setActiveGraphic( embed::getIconPixmap( + "square_wave_active" ) ); + m_sqrWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "square_wave_inactive" ) ); + toolTip::add( m_sqrWaveBtn, + tr( "Click here if you want a square-wave for " + "current oscillator." ) ); + connect( m_sqrWaveBtn, SIGNAL ( clicked ( void ) ), + this, SLOT ( sqrWaveClicked( void ) ) ); + + + m_whiteNoiseWaveBtn = new pixmapButton( this, eng() ); + m_whiteNoiseWaveBtn->move( 136, 71 ); + m_whiteNoiseWaveBtn->setActiveGraphic( + embed::getIconPixmap( "white_noise_wave_active" ) ); + m_whiteNoiseWaveBtn->setInactiveGraphic( + embed::getIconPixmap( "white_noise_wave_inactive" ) ); + toolTip::add( m_whiteNoiseWaveBtn, + tr( "Click here if you want a white-noise for " + "current oscillator." ) ); + connect( m_whiteNoiseWaveBtn, SIGNAL ( clicked ( void ) ), + this, SLOT ( noiseWaveClicked( void ) ) ); + + + m_usrWaveBtn = new pixmapButton( this, eng() ); + m_usrWaveBtn->move( 136, 88 ); + m_usrWaveBtn->setActiveGraphic( embed::getIconPixmap( + "usr_wave_active" ) ); + m_usrWaveBtn->setInactiveGraphic( embed::getIconPixmap( + "usr_wave_inactive" ) ); + toolTip::add( m_usrWaveBtn, + tr( "Click here if you want a user-defined " + "wave-shape for current oscillator." ) ); + connect( m_usrWaveBtn, SIGNAL ( clicked ( void ) ), + this, SLOT ( usrWaveClicked( void ) ) ); + + + m_smoothBtn = new pixmapButton( this, eng() ); + m_smoothBtn->move( 3, 108 ); + m_smoothBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "smooth_active" ) ); + m_smoothBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "smooth_inactive" ) ); + m_smoothBtn->setChecked( FALSE ); + toolTip::add( m_smoothBtn, + tr( "Click here to smooth waveform." ) ); + connect( m_smoothBtn, SIGNAL ( clicked ( void ) ), + this, SLOT ( smoothClicked( void ) ) ); + + + m_normalizeBtn = new pixmapButton( this, eng() ); + m_normalizeBtn->move( 20, 108 ); + m_normalizeBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "normalize_active" ) ); + m_normalizeBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "normalize_inactive" ) ); + m_normalizeBtn->setChecked( FALSE ); + toolTip::add( m_normalizeBtn, + tr( "Click here to normalize waveform." ) ); + + connect( m_normalizeBtn, SIGNAL ( clicked ( void ) ), + this, SLOT ( normalizeClicked( void ) ) ); + + m_state = new ledCheckBox( "", this, eng() ); + m_state->move( 136, 109 ); + m_state->setChecked( TRUE ); + toolTip::add( m_state, + tr( "Click here to enable/disable waveform." ) ); + + m_sampleShape = new float[m_sampleLength]; + m_graph->setSamplePointer( m_sampleShape, m_sampleLength ); + + m_lastBtn = m_sinWaveBtn; + emit( sinWaveClicked() ); + + move( _x, _y ); + +} + + + + +impulseEditor::~impulseEditor() +{ +} + + + + +void impulseEditor::sinWaveClicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_sinWaveBtn; + m_lastBtn->setChecked( TRUE ); + // generate a Sinus wave using static oscillator-method + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] = oscillator::sinSample( i / + static_cast( m_sampleLength ) ); + } + + sampleChanged(); +} + + + + +void impulseEditor::triangleWaveClicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_triangleWaveBtn; + m_lastBtn->setChecked( TRUE ); + // generate a Triangle wave using static oscillator-method + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] = oscillator::triangleSample( i / + static_cast( m_sampleLength ) ); + } + + sampleChanged(); + +} + + + + +void impulseEditor::sawWaveClicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_sawWaveBtn; + m_lastBtn->setChecked( TRUE ); + // generate a Saw wave using static oscillator-method + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] = oscillator::sawSample( i / + static_cast( m_sampleLength ) ); + } + + sampleChanged(); +} + + + + +void impulseEditor::sqrWaveClicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_sqrWaveBtn; + m_lastBtn->setChecked( TRUE ); + // generate a Sqr wave using static oscillator-method + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] = oscillator::squareSample( i / + static_cast( m_sampleLength ) ); + } + + sampleChanged(); +} + + + + +void impulseEditor::noiseWaveClicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_whiteNoiseWaveBtn; + m_lastBtn->setChecked( TRUE ); + // generate a Noise wave using static oscillator-method + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] = oscillator::noiseSample( i / + static_cast( m_sampleLength ) ); + } + + sampleChanged(); + +} + + + + +void impulseEditor::usrWaveClicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_usrWaveBtn; + m_lastBtn->setChecked( TRUE ); + // zero sample_shape + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] = 0; + } + + // load user shape + sampleBuffer buffer( eng() ); + QString af = buffer.openAudioFile(); + if( af != "" ) + { + buffer.setAudioFile( af ); + + // copy buffer data + if( m_sampleLength < static_cast( buffer.frames() ) ) + { + m_sampleLength = m_sampleLength; + } + else + { + m_sampleLength = static_cast( buffer.frames() ); + } + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] = static_cast( + buffer.data()[0][i] ); + } + } + + sampleChanged(); +} + + + + +void impulseEditor::smoothClicked( void ) +{ + m_smoothBtn->setChecked( TRUE ); + m_smoothBtn->update(); + + float* temp = new float[m_sampleLength]; + memcpy( temp, m_sampleShape, sizeof( float ) * m_sampleLength ); + + // Smoothing + m_sampleShape[0] = temp[0] / 2.0f; + for( Uint32 i = 1; i < m_sampleLength - 1; i++ ) + { + m_sampleShape[i] = ( temp[i - 1] + + temp[i] + + temp[i + 1] ) / 3.0f; + } + m_sampleShape[m_sampleLength - 1] = temp[m_sampleLength - 1] / 2.0f; + m_forward = FALSE; + + // Clean up + delete[] temp; + + // paint + update(); + m_graph->update(); + + eng()->getSongEditor()->setModified(); + + m_smoothBtn->setChecked( FALSE ); + m_smoothBtn->update(); +} + + + + +void impulseEditor::normalizeClicked( void ) +{ + m_normalizeBtn->setChecked( TRUE ); + m_normalizeBtn->update(); + + float max = 0.0001f; + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + if( fabsf(m_sampleShape[i]) > max && m_sampleShape[i] != 0.0f ) + { + max = fabs( m_sampleShape[i] ); + } + } + m_normalizeFactor = max; + + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] /= m_normalizeFactor; + } + + update(); + m_graph->update(); + + eng()->getSongEditor()->setModified(); + + m_normalizeBtn->setChecked( FALSE ); + m_normalizeBtn->update(); +} + + + + +void impulseEditor::sampleChanged() +{ + // analyze + float max = 0.0001f; + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + if( fabsf(m_sampleShape[i]) > max && m_sampleShape[i] != 0.0f ) + { + max = fabs( m_sampleShape[i] ); + } + } + m_normalizeFactor = max; + + // update + if( m_graph != NULL ) + { + m_graph->update(); + } + + eng()->getSongEditor()->setModified(); +} + + + + +void impulseEditor::setOn( bool _on ) +{ + if( _on ) + { + m_state->setChecked( TRUE ); + } + else + { + m_state->setChecked( FALSE ); + } +} + + + + +void impulseEditor::contextMenuEvent( QContextMenuEvent * ) +{ + QMenu contextMenu( this ); +#ifdef QT4 + contextMenu.setTitle( accessibleName() ); +#else + QLabel * caption = new QLabel( "" + + QString( "Impulse Editor" ) + "", this ); + caption->setPaletteBackgroundColor( QColor( 0, 0, 192 ) ); + caption->setAlignment( Qt::AlignCenter ); + contextMenu.addAction( caption ); +#endif + contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), + this, SLOT( displayHelp() ) ); + contextMenu.exec( QCursor::pos() ); +} + + + + +void impulseEditor::displayHelp( void ) +{ +#ifdef QT4 + QWhatsThis::showText( mapToGlobal( rect().bottomRight() ), + whatsThis() ); +#else + QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal( + rect().bottomRight() ) ); +#endif +} + + + + +void FASTCALL impulseEditor::setValues( float * _shape ) +{ + for( Uint32 i = 0; i < m_sampleLength; i++ ) + { + m_sampleShape[i] = _shape[i]; + } +} + + + + +#include "impulse_editor.moc" + diff --git a/plugins/vibed/impulse_editor.h b/plugins/vibed/impulse_editor.h new file mode 100644 index 000000000..a57de143a --- /dev/null +++ b/plugins/vibed/impulse_editor.h @@ -0,0 +1,99 @@ +/* + * impulse_editor.cpp - graphic waveform editor + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#ifndef _IMPULSE_EDITOR_H +#define _IMPULSE_EDITOR_H + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +#include + +#else + +#include +#include +#include + +#endif + +#include "config.h" +#include "types.h" +#include "graph.h" +#include "pixmap_button.h" +#include "engine.h" +#include "led_checkbox.h" + +class impulseEditor: public QWidget, public engineObject +{ + Q_OBJECT +public: + impulseEditor( QWidget *parent, int _x, int _y, + engine * _engine, Uint32 _len = 128 ); + ~impulseEditor(); + + inline float * getValues() { return( m_sampleShape ); }; + inline bool isOn() { return( m_state->isChecked() ); }; + void FASTCALL setValues( float * _shape ); + +public slots: + void sinWaveClicked( void ); + void triangleWaveClicked( void ); + void sawWaveClicked( void ); + void sqrWaveClicked( void ); + void noiseWaveClicked( void ); + void usrWaveClicked( void ); + void smoothClicked( void ); + void normalizeClicked( void ); + void sampleChanged(); + void setOn( bool _on ); + void contextMenuEvent( QContextMenuEvent * ); + void displayHelp( void ); + +private: + + graph * m_graph; + pixmapButton * m_sinWaveBtn; + pixmapButton * m_triangleWaveBtn; + pixmapButton * m_sqrWaveBtn; + pixmapButton * m_sawWaveBtn; + pixmapButton * m_whiteNoiseWaveBtn; + pixmapButton * m_usrWaveBtn; + pixmapButton * m_smoothBtn; + pixmapButton * m_normalizeBtn; + pixmapButton * m_lastBtn; + ledCheckBox * m_state; + + float * m_sampleShape; + + Uint32 m_sampleLength; + float m_normalizeFactor; + bool m_forward; + + QPixmap m_base; +}; + +#endif diff --git a/plugins/vibed/logo.png b/plugins/vibed/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ad8ab99a7fc492bb6f9b7bfa29ef10bb902a282c GIT binary patch literal 5211 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 VVIJ2R4uJpw002ovPDHLkV1i+x{!;(| literal 0 HcmV?d00001 diff --git a/plugins/vibed/nine_button_selector.cpp b/plugins/vibed/nine_button_selector.cpp new file mode 100644 index 000000000..584f0e296 --- /dev/null +++ b/plugins/vibed/nine_button_selector.cpp @@ -0,0 +1,318 @@ +/* + * nine_button_selector.cpp + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifdef QT4 + +#include +#include + +#else + +#include +#include +#include +#include + +#endif + + +#include "nine_button_selector.h" +#include "embed.h" + +nineButtonSelector::nineButtonSelector( QPixmap _button0_on, + QPixmap _button0_off, + QPixmap _button1_on, + QPixmap _button1_off, + QPixmap _button2_on, + QPixmap _button2_off, + QPixmap _button3_on, + QPixmap _button3_off, + QPixmap _button4_on, + QPixmap _button4_off, + QPixmap _button5_on, + QPixmap _button5_off, + QPixmap _button6_on, + QPixmap _button6_off, + QPixmap _button7_on, + QPixmap _button7_off, + QPixmap _button8_on, + QPixmap _button8_off, + Uint8 _default, + Uint32 _x, Uint32 _y, + QWidget * _parent, + engine * _engine ): + QWidget( _parent, "nineButtonSelector" ), + engineObject( _engine ), + m_selected( _default ) +{ + setFixedSize( 50, 50 ); + m_base = QPixmap::grabWidget( _parent, _x, _y ); + move( _x, _y ); + setPaletteBackgroundPixmap( m_base ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 1, 1 ); + m_button->setActiveGraphic( _button0_on ); + m_button->setInactiveGraphic( _button0_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button0Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 18, 1 ); + m_button->setActiveGraphic( _button1_on ); + m_button->setInactiveGraphic( _button1_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button1Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 35, 1 ); + m_button->setActiveGraphic( _button2_on ); + m_button->setInactiveGraphic( _button2_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button2Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 1, 18 ); + m_button->setActiveGraphic( _button3_on ); + m_button->setInactiveGraphic( _button3_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button3Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 18, 18 ); + m_button->setActiveGraphic( _button4_on ); + m_button->setInactiveGraphic( _button4_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button4Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 35, 18 ); + m_button->setActiveGraphic( _button5_on ); + m_button->setInactiveGraphic( _button5_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button5Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 1, 35 ); + m_button->setActiveGraphic( _button6_on ); + m_button->setInactiveGraphic( _button6_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button6Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 18, 35 ); + m_button->setActiveGraphic( _button7_on ); + m_button->setInactiveGraphic( _button7_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button7Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_button = new pixmapButton( this, eng() ); + m_button->move( 35, 35 ); + m_button->setActiveGraphic( _button8_on ); + m_button->setInactiveGraphic( _button8_off ); + m_button->setChecked( FALSE ); + connect( m_button, SIGNAL ( clicked ( void ) ), + this, SLOT ( button8Clicked( void ) ) ); + m_buttons.append( m_button ); + + m_lastBtn = m_buttons.at( _default ); + m_lastBtn->setChecked( TRUE ); +} + + +nineButtonSelector::~ nineButtonSelector() +{ +} + + + + +void nineButtonSelector::button0Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 0 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 0; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::button1Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 1 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 1; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::button2Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 2 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 2; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::button3Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 3 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 3; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::button4Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 4 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 4; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::button5Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 5 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 5; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::button6Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 6 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 6; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::button7Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 7 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 7; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::button8Clicked( void ) +{ + m_lastBtn->setChecked( FALSE); + m_lastBtn = m_buttons.at( 8 ); + m_lastBtn->setChecked( TRUE ); + + m_selected = 8; + emit nineButtonSelection( m_selected ); +} + + + + +void nineButtonSelector::contextMenuEvent( QContextMenuEvent * ) +{ + QMenu contextMenu( this ); +#ifdef QT4 + contextMenu.setTitle( accessibleName() ); +#else + QLabel * caption = new QLabel( "" + + QString( "Selector" ) + "", this ); + caption->setPaletteBackgroundColor( QColor( 0, 0, 192 ) ); + caption->setAlignment( Qt::AlignCenter ); + contextMenu.addAction( caption ); +#endif + contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), + this, SLOT( displayHelp() ) ); + contextMenu.exec( QCursor::pos() ); +} + + + + +void nineButtonSelector::displayHelp( void ) +{ +#ifdef QT4 + QWhatsThis::showText( mapToGlobal( rect().bottomRight() ), + whatsThis() ); +#else + QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal( + rect().bottomRight() ) ); +#endif +} + + + + +#include "nine_button_selector.moc" diff --git a/plugins/vibed/nine_button_selector.h b/plugins/vibed/nine_button_selector.h new file mode 100644 index 000000000..153b02a90 --- /dev/null +++ b/plugins/vibed/nine_button_selector.h @@ -0,0 +1,89 @@ +/* + * nine_button_selector.h + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#ifndef _NINE_BUTTON_SELECTOR_H +#define _NINE_BUTTON_SELECTOR_H + +#include + +#include "qt3support.h" +#include "config.h" +#include "types.h" +#include "pixmap_button.h" + +class nineButtonSelector: public QWidget, public engineObject +{ + Q_OBJECT + +public: + nineButtonSelector( QPixmap _button1_on, + QPixmap _button1_off, + QPixmap _button2_on, + QPixmap _button2_off, + QPixmap _button3_on, + QPixmap _button3_off, + QPixmap _button4_on, + QPixmap _button4_off, + QPixmap _button5_on, + QPixmap _button5_off, + QPixmap _button6_on, + QPixmap _button6_off, + QPixmap _button7_on, + QPixmap _button7_off, + QPixmap _button8_on, + QPixmap _button8_off, + QPixmap _button9_on, + QPixmap _button9_off, + Uint8 _default, + Uint32 _x, Uint32 _y, + QWidget * _parent, + engine * _engine ); + ~nineButtonSelector(); + + inline Uint8 getSelected() { return( m_selected ); }; + +public slots: + void button0Clicked( void ); + void button1Clicked( void ); + void button2Clicked( void ); + void button3Clicked( void ); + void button4Clicked( void ); + void button5Clicked( void ); + void button6Clicked( void ); + void button7Clicked( void ); + void button8Clicked( void ); + void contextMenuEvent( QContextMenuEvent * ); + void displayHelp( void ); + +signals: + void nineButtonSelection( Uint8 ); + +private: + QPtrList m_buttons; + pixmapButton * m_button; + pixmapButton * m_lastBtn; + QPixmap m_base; + + Uint8 m_selected; +}; +#endif diff --git a/plugins/vibed/normalize_active.png b/plugins/vibed/normalize_active.png new file mode 100644 index 0000000000000000000000000000000000000000..bc57226a4d498e773e7335d324dd7ccb5e3526ce GIT binary patch literal 469 zcmV;`0V@89P)GW=`UZ?h6!+x{z zWUok8dqi1ao*1;&+GtPlpy=gj9Z1B3MsvH}A5_x;0PV$qa5!XW zF9GHNiOtQ(y_IX@F9qm#g2a*RzcIOE{jQvsSa~`4#(vU(@IT-;n+$7n*Ih^400000 LNkvXXu0mjf8{EM; literal 0 HcmV?d00001 diff --git a/plugins/vibed/normalize_inactive.png b/plugins/vibed/normalize_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..3d5af0882496bbd03e4a448e73c64daf7b5cb3f6 GIT binary patch literal 477 zcmV<30V4j1P)RaF^{M)>`HWLai79J(Ugw!fed0wDwd zk|a3-uh+|XJSG?n0(?NrvY3-)w$o{Z5L60-s$mdQ6ynh+0A1VWqFkO9NdPU=q*kwU zr0W306oo;*&vm83)y)b3da+2$G-;V803J=#Ce3DJ+VpgH&){vq^UEu%=@j#!5Vw~F z7MEkwJB>yY#|Itc4_OF@$z?WONAfuxK0MaY3k6ciB;8)m5lU{2`O_1uPKTXr_IJ1x zi2$$?j}r_8*xlbl{`{sN;nvzZ0J)6}Y9c|a-RAiG%n^QDb(XlUI!ipjYhW{YAVDIwDKoQOYkH}&M z25w;xW@MN(M*=9wUgGKN%6^TRM}R|ilg-s=ppa~dYeb22er|4RUI~M9QEFmIYKlU6 zW=V!ZNJgrHyQgo!`xMnY1_nkSPZ!4!jq`ISoz-&=6lmCgx!5oN{nyO`UxkxWuj(D~ z>QLV>L7EaS&Cx#7>K8CvdTDY@BIbIown(?@rkiitS8R35{<~UX>5(XJ8@d0lA~Zx^o%C{VZ9eI| zu03zVC8L7-=bg_hch6)^5?x+-rMqUIoJE|aGmF6{>z-b=JAU^c9ujnDsT$!fBfYB3rlPkS}X|M?{EC!P!wJXGwh%pRqP=u6wZicr#LedTh=^u3b6 z+UQ)BZIZ6CUT0d4_ObmaW-C?scx|z7QFlb_*TOQBjcYX+9P=G2e^1?@?=q!MFxyzn zSnk0a%@qwZH+2|wJU3h1Wz^EFxc;G?Mi_($>1ME0Dh2~Ni=;z0o0qXf*o29gB$lp3ns#W7B08flv;&5wLn}%y zqOJzl^u-`KstA7L@A-e8C;#MWa=YC%{+M7eh#5dp6w2i?7K;T*k|>o*-=bVD_YOr- zL=;5;OeWKpKoA5fl?t*f1H8d>I&B=bS*?sYopg6~AqWCD`8>Avc6@$6TCr$cWCpmp zzBY>Wr6p?BD*K@j&632J%Y~(-g>X zczArQhaa;W2(YuU$!Q`%I+Niv5ocslY24Z2aIC7TY7{5&7_np$YilcgJ-tkOJU9mW zIgCV%8C6vqUtC*WVJ{e9+vfwoCd(X$!q{y#?mqAMF;j}d(BL3}gD}PCXGVvIdD1ir zg+kq21ANjnIy*Y>&dsCiI;qP`W){4>==#slIWhjLZ)f74X##5hfv?JzfEMI(q;UWM N002ovPDHLkV1kyX)b;=X literal 0 HcmV?d00001 diff --git a/plugins/vibed/string_container.cpp b/plugins/vibed/string_container.cpp new file mode 100644 index 000000000..c005e3e2c --- /dev/null +++ b/plugins/vibed/string_container.cpp @@ -0,0 +1,95 @@ +/* + * string_container.cpp - contains a collection of strings + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "string_container.h" + + +stringContainer::stringContainer( const float _pitch, + const sample_rate_t _sample_rate, + const Uint32 _buffer_length ) : + m_pitch( _pitch ), + m_sampleRate( _sample_rate ), + m_bufferLength( _buffer_length ) +{ +} + + + + +void stringContainer::addString(Uint8 _harm, + const float _pick, + const float _pickup, + float * _impluse, + const float _randomize, + const float _string_loss, + const float _detune, + const Uint8 _oversample, + const bool _state ) +{ + float harm; + switch( _harm ) + { + case 0: + harm = 0.25f; + break; + case 1: + harm = 0.5f; + break; + case 2: + harm = 1.0f; + break; + case 3: + harm = 2.0f; + break; + case 4: + harm = 3.0f; + break; + case 5: + harm = 4.0f; + break; + case 6: + harm = 5.0f; + break; + case 7: + harm = 6.0f; + break; + case 8: + harm = 7.0f; + break; + default: + harm = 1.0f; + } + + m_strings.append( new vibratingString( m_pitch * harm, + _pick, + _pickup, + _impluse, + m_bufferLength, + m_sampleRate, + _oversample, + _randomize, + _string_loss, + _detune, + _state ) ); +} diff --git a/plugins/vibed/string_container.h b/plugins/vibed/string_container.h new file mode 100644 index 000000000..7812c3ca5 --- /dev/null +++ b/plugins/vibed/string_container.h @@ -0,0 +1,83 @@ +/* string_container.h - contains a collection of strings + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#ifndef _TWO_STRINGS_H +#define _TWO_STRINGS_H + + +#ifdef QT4 + +#include + +#else + +#include "qptrlist.h" + +#endif + + +#include "config.h" +#include "types.h" +#include "vibrating_string.h" + + + +class stringContainer +{ +public: + stringContainer( const float _pitch, + const sample_rate_t _sample_rate, + const Uint32 _buffer_length ); + + void addString( Uint8 _harm, + const float _pick, + const float _pickup, + float * _impluse, + const float _randomize, + const float _string_loss, + const float _detune, + const Uint8 _oversample, + const bool _state ); + + inline ~stringContainer() + { + m_strings.setAutoDelete( TRUE ); + Uint32 strings = m_strings.count(); + for( Uint32 i = 0; i < strings; i++ ) + { + m_strings.removeFirst(); + } + } + + inline float getStringSample( Uint8 _string ) + { + return( m_strings.at( _string )->nextSample() ); + } + +private: + QPtrList m_strings; + const float m_pitch; + const sample_rate_t m_sampleRate; + const Uint32 m_bufferLength; +} ; + +#endif diff --git a/plugins/vibed/vibed.cpp b/plugins/vibed/vibed.cpp new file mode 100644 index 000000000..397f15490 --- /dev/null +++ b/plugins/vibed/vibed.cpp @@ -0,0 +1,747 @@ +/* + * vibed.cpp - combination of PluckedStringSynth and BitInvader + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +#include +#include + +#else + +#include +#include +#include +#include +#include +#include + +#endif + + +#include "vibed.h" +#include "note_play_handle.h" +#include "instrument_track.h" +#include "templates.h" +#include "buffer_allocator.h" +#include "knob.h" +#include "tooltip.h" +#include "oscillator.h" +#include "song_editor.h" +#include "string_container.h" +#include "base64.h" + +#undef SINGLE_SOURCE_COMPILE +#include "embed.cpp" + + +extern "C" +{ + +plugin::descriptor vibedstrings_plugin_descriptor = +{ + STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ), + "Vibed", + QT_TRANSLATE_NOOP( "pluginBrowser", + "Vibrating string modeler" ), + "Danny McRae ", + 0x0100, + plugin::INSTRUMENT, + new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ) +}; + +} + + +vibed::vibed( instrumentTrack * _channel_track ) : + instrument( _channel_track, &vibedstrings_plugin_descriptor ), + m_sampleLength( 128 ) +{ +#ifdef QT4 + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( + "artwork" ) ); + setPalette( pal ); +#else + setErasePixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) ); +#endif + + for( Uint8 harm = 0; harm < 9; harm++ ) + { + m_editor = new impulseEditor( this, 76, 21, eng() ); + m_editor->setOn( FALSE ); + m_editor->hide(); + m_editors.append( m_editor ); +#ifdef QT4 + m_editor->setWhatsThis( +#else + QWhatsThis::add( m_editor, +#endif + tr( +"The waveform editor provides control over the initial state or impulse " +"that is used to start the string vibrating. The buttons to the right of " +"the graph will initialize the waveform to the selected type. The '?' " +"button will load a waveform from a file--only the first 128 samples " +"will be loaded.\n\n" + +"The waveform can also be drawn in the graph.\n\n" + +"The 'S' button will smooth the waveform.\n\n" + +"The 'N' button will normalize the waveform.") ); + + m_volumeKnob = new knob( knobBright_26, this, + tr( "Volume" ), + eng() ); + m_volumeKnob->setRange( 0.0f, 2.0f, 0.01f ); + m_volumeKnob->setInitValue( 1.0f ); + m_volumeKnob->move( 103, 142 ); + m_volumeKnob->setHintText( tr( "Volume:" ) + " ", "" ); + m_volumeKnob->hide(); + m_volumeKnobs.append( m_volumeKnob ); +#ifdef QT4 + m_volumeKnob->setWhatsThis( +#else + QWhatsThis::add( m_volumeKnob, +#endif + tr( +"The 'V' knob sets the volume of the selected string." ) ); + + m_stiffnessKnob = new knob( knobBright_26, this, + tr( "String stiffness" ), + eng() ); + m_stiffnessKnob->setRange( 0.0f, 0.05f, 0.001f ); + m_stiffnessKnob->setInitValue( 0.0f ); + m_stiffnessKnob->move( 129, 142 ); + m_stiffnessKnob->setHintText( tr( "String stiffness:" ) + + " ", "" ); + m_stiffnessKnob->hide(); + m_stiffnessKnobs.append( m_stiffnessKnob ); +#ifdef QT4 + m_stiffnessKnob->setWhatsThis( +#else + QWhatsThis::add( m_stiffnessKnob, +#endif + tr( +"The 'S' knob sets the stiffness of the selected string. The stiffness " +"of the string affects how long the string will ring out. The lower " +"the setting, the longer the string will ring." ) ); + + + m_pickKnob = new knob( knobBright_26, this, + tr( "Pick position" ), + eng() ); + m_pickKnob->setRange( 0.0f, 0.5f, 0.005f ); + m_pickKnob->setInitValue( 0.0f ); + m_pickKnob->move( 153, 142 ); + m_pickKnob->setHintText( tr( "Pick position:" ) + " ", "" ); + m_pickKnob->hide(); + m_pickKnobs.append( m_pickKnob ); +#ifdef QT4 + m_pickKnob->setWhatsThis( +#else + QWhatsThis::add( m_pickKnob, +#endif + tr( +"The 'P' knob sets the position where the selected string will be 'picked'. " +"The lower the setting the closer the pick is to the bridge." ) ); + + m_pickupKnob = new knob( knobBright_26, this, + tr( "Pickup position" ), + eng() ); + m_pickupKnob->setRange( 0.0f, 0.5f, 0.005f ); + m_pickupKnob->setInitValue( 0.05f ); + m_pickupKnob->move( 177, 142 ); + m_pickupKnob->setHintText( tr( "Pickup position:" ) + + " ", "" ); + m_pickupKnob->hide(); + m_pickupKnobs.append( m_pickupKnob ); +#ifdef QT4 + m_pickupKnob->setWhatsThis( +#else + QWhatsThis::add( m_pickupKnob, +#endif + tr( +"The 'PU' knob sets the position where the vibrations will be monitored " +"for the selected string. The lower the setting, the closer the " +"pickup is to the bridge." ) ); + + m_panKnob = new knob( knobBright_26, this, + tr( "Pan" ), + eng() ); + m_panKnob->setRange( -1.0f, 1.0f, 0.01f ); + m_panKnob->setInitValue( 0.0f ); + m_panKnob->move( 105, 187 ); + m_panKnob->setHintText( tr( "Pan:" ) + " ", "" ); + m_panKnob->hide(); + m_panKnobs.append( m_panKnob ); +#ifdef QT4 + m_panKnob->setWhatsThis( +#else + QWhatsThis::add( m_panKnob, +#endif + tr( +"The Pan knob determines the location of the selected string in the stereo " +"field." ) ); + + m_detuneKnob = new knob( knobBright_26, this, + tr( "Detune" ), + eng() ); + m_detuneKnob->setRange( -0.1f, 0.1f, 0.001f ); + m_detuneKnob->setInitValue( 0.0f ); + m_detuneKnob->move( 150, 187 ); + m_detuneKnob->setHintText( tr( "Detune:" ) + " ", "" ); + m_detuneKnob->hide(); + m_detuneKnobs.append( m_detuneKnob ); +#ifdef QT4 + m_detuneKnob->setWhatsThis( +#else + QWhatsThis::add( m_detuneKnob, +#endif + tr( +"The Detune knob modifies the pitch of the selected string. Settings less " +"than zero will cause the string to sound flat. Settings greater than zero " +"will cause the string to sound sharp." ) ); + + m_randomKnob = new knob( knobBright_26, this, + tr( "Fuzziness" ), + eng() ); + m_randomKnob->setRange( 0.0f, 0.75f, 0.01f ); + m_randomKnob->setInitValue( 0.0f ); + m_randomKnob->move( 194, 187 ); + m_randomKnob->setHintText( tr( "Fuzziness:" ) + + " ", "" ); + m_randomKnob->hide(); + m_randomKnobs.append( m_randomKnob ); +#ifdef QT4 + m_randomKnob->setWhatsThis( +#else + QWhatsThis::add( m_randomKnob, +#endif + tr( +"The Slap knob adds a bit of fuzz to the selected string which is most " +"apparent during the attack, though it can also be used to make the string " +"sound more 'metallic'.") ); + + m_lengthKnob = new knob( knobBright_26, this, + tr( "Length" ), + eng() ); + m_lengthKnob->setRange( 1, 16, 1 ); + m_lengthKnob->setInitValue( 1 ); + m_lengthKnob->move( 23, 193 ); + m_lengthKnob->setHintText( tr( "Length:" ) + + " ", "" ); + m_lengthKnob->hide(); + m_lengthKnobs.append( m_lengthKnob ); +#ifdef QT4 + m_lengthKnob->setWhatsThis( +#else + QWhatsThis::add( m_lengthKnob, +#endif + tr( +"The Length knob sets the length of the selected string. Longer strings " +"will both ring longer and sound brighter, however, they will also eat up " +"more CPU cycles." ) ); + + m_impulse = new ledCheckBox( "", this, eng() ); + m_impulse->move( 23, 94 ); + m_impulse->setChecked( FALSE ); + toolTip::add( m_impulse, + tr( "Impulse or initial state" ) ); + m_impulse->hide(); + m_impulses.append( m_impulse ); +#ifdef QT4 + m_impulse->setWhatsThis( +#else + QWhatsThis::add( m_impulse, +#endif + tr( +"The 'Imp' selector determines whether the waveform in the graph is to be " +"treated as an impulse imparted to the string by the pick or the initial " +"state of the string." ) ); + + m_harmonic = new nineButtonSelector( + PLUGIN_NAME::getIconPixmap( "button_-2_on" ), + PLUGIN_NAME::getIconPixmap( "button_-2_off" ), + PLUGIN_NAME::getIconPixmap( "button_-1_on" ), + PLUGIN_NAME::getIconPixmap( "button_-1_off" ), + PLUGIN_NAME::getIconPixmap( "button_f_on" ), + PLUGIN_NAME::getIconPixmap( "button_f_off" ), + PLUGIN_NAME::getIconPixmap( "button_2_on" ), + PLUGIN_NAME::getIconPixmap( "button_2_off" ), + PLUGIN_NAME::getIconPixmap( "button_3_on" ), + PLUGIN_NAME::getIconPixmap( "button_3_off" ), + PLUGIN_NAME::getIconPixmap( "button_4_on" ), + PLUGIN_NAME::getIconPixmap( "button_4_off" ), + PLUGIN_NAME::getIconPixmap( "button_5_on" ), + PLUGIN_NAME::getIconPixmap( "button_5_off" ), + PLUGIN_NAME::getIconPixmap( "button_6_on" ), + PLUGIN_NAME::getIconPixmap( "button_6_off" ), + PLUGIN_NAME::getIconPixmap( "button_7_on" ), + PLUGIN_NAME::getIconPixmap( "button_7_off" ), + 2, + 21, 127, + this, + eng() ); + m_harmonic->hide(); + m_harmonics.append( m_harmonic ); +#ifdef QT4 + m_harmonic->setWhatsThis( +#else + QWhatsThis::add( m_harmonic, +#endif + tr( +"The Octave selector is used to choose which harmonic of the note the " +"string will ring at. For example, '-2' means the string will ring two " +"octaves below the fundamental, 'F' means the string will ring at the " +"fundamental, and '6' means the string will ring six octaves above the " +"fundamental." ) ); + } + + m_stringSelector = new nineButtonSelector( + PLUGIN_NAME::getIconPixmap( "button_1_on" ), + PLUGIN_NAME::getIconPixmap( "button_1_off" ), + PLUGIN_NAME::getIconPixmap( "button_2_on" ), + PLUGIN_NAME::getIconPixmap( "button_2_off" ), + PLUGIN_NAME::getIconPixmap( "button_3_on" ), + PLUGIN_NAME::getIconPixmap( "button_3_off" ), + PLUGIN_NAME::getIconPixmap( "button_4_on" ), + PLUGIN_NAME::getIconPixmap( "button_4_off" ), + PLUGIN_NAME::getIconPixmap( "button_5_on" ), + PLUGIN_NAME::getIconPixmap( "button_5_off" ), + PLUGIN_NAME::getIconPixmap( "button_6_on" ), + PLUGIN_NAME::getIconPixmap( "button_6_off" ), + PLUGIN_NAME::getIconPixmap( "button_7_on" ), + PLUGIN_NAME::getIconPixmap( "button_7_off" ), + PLUGIN_NAME::getIconPixmap( "button_8_on" ), + PLUGIN_NAME::getIconPixmap( "button_8_off" ), + PLUGIN_NAME::getIconPixmap( "button_9_on" ), + PLUGIN_NAME::getIconPixmap( "button_9_off" ), + 0, + 21, 39, + this, + eng() ); + connect( m_stringSelector, SIGNAL( nineButtonSelection( Uint8 ) ), + this, SLOT( showString( Uint8 ) ) ); +#ifdef QT4 + m_stringSelector->setWhatsThis( +#else + QWhatsThis::add( m_stringSelector, +#endif + tr( +"The String selector is used to choose which string the controls are " +"editting. A Vibed instrument can contain up to nine independently " +"vibrating strings. The LED in the lower right corner of the " +"waveform editor indicates whether the selected string is active." ) ); + + m_pickKnob = m_pickKnobs.at( 0 ); + m_pickupKnob = m_pickupKnobs.at( 0 ); + m_stiffnessKnob = m_stiffnessKnobs.at( 0 ); + m_volumeKnob = m_volumeKnobs.at( 0 ); + m_panKnob = m_panKnobs.at( 0 ); + m_detuneKnob = m_detuneKnobs.at( 0 ); + m_randomKnob = m_randomKnobs.at( 0 ); + m_lengthKnob = m_lengthKnobs.at( 0 ); + m_editor = m_editors.at( 0 ); + m_impulse = m_impulses.at( 0 ); + m_harmonic = m_harmonics.at( 0 ); + + m_editor->setOn( TRUE ); + showString( 0 ); + +#ifdef QT4 + this->setWhatsThis( +#else + QWhatsThis::add( this, +#endif + tr( +"Vibed models up to nine independently vibrating strings. The 'String' " +"selector allows you to choose which string is being edited. The 'Imp' " "selector chooses whether the graph represents an impulse or the initial " +"state of the string. The 'Octave' selector chooses which harmonic the " +"string should vibrate at.\n\n" + +"The graph allows you to control the initial state or impulse used to set the " +"string in motion.\n\n" + +"The 'V' knob controls the volume. The 'S' knob controls the string's " +"stiffness. The 'P' knob controls the pick position. The 'PU' knob " +"controls the pickup position.\n\n" + +"'Pan' and 'Detune' hopefully don't need explanation. The 'Slap' knob " +"adds a bit of fuzz to the sound of the string.\n\n" + +"The 'Length' knob controls the length of the string.\n\n" + +"The LED in the lower right corner of the waveform editor determines " +"whether the string is active in the current instrument." ) ); + +} + + + + +vibed::~vibed() +{ + delete m_sampleBuffer; + m_pickKnobs.setAutoDelete( TRUE ); + m_pickupKnobs.setAutoDelete( TRUE ); + m_stiffnessKnobs.setAutoDelete( TRUE ); + m_volumeKnobs.setAutoDelete( TRUE ); + m_panKnobs.setAutoDelete( TRUE ); + m_detuneKnobs.setAutoDelete( TRUE ); + m_randomKnobs.setAutoDelete( TRUE ); + m_lengthKnobs.setAutoDelete( TRUE ); + m_editors.setAutoDelete( TRUE ); + m_impulses.setAutoDelete( TRUE ); + for( Uint8 harm = 0; harm < 9; harm++ ) + { + m_pickKnobs.removeFirst(); + m_pickupKnobs.removeFirst(); + m_stiffnessKnobs.removeFirst(); + m_volumeKnobs.removeFirst(); + m_panKnobs.removeFirst(); + m_detuneKnobs.removeFirst(); + m_randomKnobs.removeFirst(); + m_lengthKnobs.removeFirst(); + m_editors.removeFirst(); + m_impulses.removeFirst(); + m_harmonics.removeFirst(); + } +} + + + + +void vibed::saveSettings( QDomDocument & _doc, + QDomElement & _this ) +{ + QString name; + + // Save plugin version + _this.setAttribute( "version", "0.1" ); + + for( Uint8 i = 0; i < 9; i++ ) + { + name = "active" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_editors.at( i )->isOn() ) ); + if( m_editors.at( i )->isOn() ) + { + name = "volume" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_volumeKnobs.at( i )->value() ) ); + + name = "stiffness" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_stiffnessKnobs.at( i )->value() ) ); + + name = "pick" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_pickKnobs.at( i )->value() ) ); + + name = "pickup" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_pickupKnobs.at( i )->value() ) ); + + name = "length" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_lengthKnobs.at( i )->value() ) ); + + name = "pan" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_panKnobs.at( i )->value() ) ); + + name = "detune" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_detuneKnobs.at( i )->value() ) ); + + name = "slap" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_randomKnobs.at( i )->value() ) ); + + name = "impulse" + QString::number( i ); + _this.setAttribute( name, QString::number( + m_impulses.at( i )->isChecked() ) ); + + QString sampleString; + base64::encode( + (const char *)m_editors.at( i )->getValues(), + 128 * sizeof(float), sampleString ); + name = "graph" + QString::number( i ); + _this.setAttribute( name, sampleString ); + } + } + +} + + + + +void vibed::loadSettings( const QDomElement & _this ) +{ + QString name; + + for( Uint8 i = 0; i < 9; i++ ) + { + name = "active" + QString::number( i ); + m_editors.at( i )->setOn( _this.attribute( name ).toInt() ); + + if( m_editors.at( i )->isOn() ) + { + name = "volume" + QString::number( i ); + m_volumeKnobs.at( i )->setValue( + _this.attribute( name ).toFloat() ); + + name = "stiffness" + QString::number( i ); + m_stiffnessKnobs.at( i )->setValue( + _this.attribute( name ).toFloat() ); + + name = "pick" + QString::number( i ); + m_pickKnobs.at( i )->setValue( + _this.attribute( name ).toFloat() ); + + name = "pickup" + QString::number( i ); + m_pickupKnobs.at( i )->setValue( + _this.attribute( name ).toFloat() ); + + name = "length" + QString::number( i ); + m_lengthKnobs.at( i )->setValue( + _this.attribute( name ).toFloat() ); + + name = "pan" + QString::number( i ); + m_panKnobs.at( i )->setValue( + _this.attribute( name ).toFloat() ); + + name = "detune" + QString::number( i ); + m_detuneKnobs.at( i )->setValue( + _this.attribute( name ).toFloat() ); + + name = "slap" + QString::number( i ); + m_randomKnobs.at( i )->setValue( + _this.attribute( name ).toFloat() ); + + name = "impulse" + QString::number( i ); + m_impulses.at( i )->setChecked( + _this.attribute( name ).toInt() ); + + name = "graph" + QString::number( i ); + float shape[128]; + int size = 0; + QString sampleString = _this.attribute( name ); + char * dst = 0; + base64::decode( sampleString, &dst, &size ); + memcpy( shape, dst, size ); + m_editors.at( i )->setValues( shape ); + } + } + + update(); +} + + + + +QString vibed::nodeName( void ) const +{ + return( vibedstrings_plugin_descriptor.name ); +} + + + + +void vibed::playNote( notePlayHandle * _n ) +{ + if ( _n->totalFramesPlayed() == 0 ) + { + float freq = getInstrumentTrack()->frequency( _n ); + + _n->m_pluginData = new stringContainer( + freq, + eng()->getMixer()->sampleRate(), + m_sampleLength ); + + for( Uint8 i = 0; i < 9; i++ ) + { + if( m_editors.at( i )->isOn() ) + { + static_cast( + _n->m_pluginData )->addString( + m_harmonics.at( i )->getSelected(), + m_pickKnobs.at( i )->value(), + m_pickupKnobs.at( i )->value(), + m_editors.at( i )->getValues(), + m_randomKnobs.at( i )->value(), + m_stiffnessKnobs.at( i )->value(), + m_detuneKnobs.at( i )->value(), + static_cast( + m_lengthKnobs.at( i )->value() ), + m_impulses.at( i )->isChecked() ); + } + } + } + + const Uint32 frames = eng()->getMixer()->framesPerAudioBuffer(); + stringContainer * ps = static_cast( + _n->m_pluginData ); + + sampleFrame * buf = bufferAllocator::alloc( frames ); + + float vol; + float pan; + float sample; + Uint8 s; + + for( Uint32 i = 0; i < frames; i++ ) + { + buf[i][0] = 0.0f; + buf[i][1] = 0.0f; + s = 0; + for( Uint8 string = 0; string < 9; string ++ ) + { + if( m_editors.at( string )->isOn() ) + { + vol = m_volumeKnobs.at( + string )->value(); + pan = ( + m_panKnobs.at( string )->value() + 1 ) / 2.0; + sample = ps->getStringSample( s ); + + buf[i][0] += pan * vol * sample; + buf[i][1] += ( 1.0 - pan ) * vol * sample; + s++; + } + } + } + + getInstrumentTrack()->processAudioBuffer( buf, frames, _n ); + + bufferAllocator::free( buf ); +} + + + + +void vibed::deleteNotePluginData( notePlayHandle * _n ) +{ + delete static_cast( _n->m_pluginData ); +} + + + + +void vibed::showString( Uint8 _string ) +{ + m_pickKnob->hide(); + m_pickupKnob->hide(); + m_stiffnessKnob->hide(); + m_volumeKnob->hide(); + m_panKnob->hide(); + m_detuneKnob->hide(); + m_randomKnob->hide(); + m_lengthKnob->hide(); + m_editor->hide(); + m_impulse->hide(); + m_harmonic->hide(); + + m_editors.at( _string )->show(); + m_volumeKnobs.at( _string )->show(); + m_stiffnessKnobs.at( _string )->show(); + m_pickKnobs.at( _string )->show(); + m_pickupKnobs.at( _string )->show(); + m_panKnobs.at( _string )->show(); + m_detuneKnobs.at( _string )->show(); + m_randomKnobs.at( _string )->show(); + m_lengthKnobs.at( _string )->show(); + m_impulses.at( _string )->show(); + m_impulses.at( _string )->update(); + m_harmonics.at( _string )->show(); + + m_pickKnob = m_pickKnobs.at( _string ); + m_pickupKnob = m_pickupKnobs.at( _string ); + m_stiffnessKnob = m_stiffnessKnobs.at( _string ); + m_volumeKnob = m_volumeKnobs.at( _string ); + m_panKnob = m_panKnobs.at( _string ); + m_detuneKnob = m_detuneKnobs.at( _string ); + m_randomKnob = m_randomKnobs.at( _string ); + m_lengthKnob = m_lengthKnobs.at( _string ); + m_editor = m_editors.at( _string ); + m_impulse = m_impulses.at( _string ); + m_harmonic = m_harmonics.at( _string ); +} + + + + + +void vibed::contextMenuEvent( QContextMenuEvent * ) +{ + QMenu contextMenu( this ); +#ifdef QT4 + contextMenu.setTitle( accessibleName() ); +#else + QLabel * caption = new QLabel( "" + + QString( "Vibed" ) + "", this ); + caption->setPaletteBackgroundColor( QColor( 0, 0, 192 ) ); + caption->setAlignment( Qt::AlignCenter ); + contextMenu.addAction( caption ); +#endif + contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), + this, SLOT( displayHelp() ) ); + contextMenu.exec( QCursor::pos() ); +} + + + + +void vibed::displayHelp( void ) +{ +#ifdef QT4 + QWhatsThis::showText( mapToGlobal( rect().bottomRight() ), + whatsThis() ); +#else + QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal( + rect().bottomRight() ) ); +#endif +} + + + + +extern "C" +{ + +// neccessary for getting instance out of shared lib + plugin * lmms_plugin_main( void * _data ) + { + return( new vibed( static_cast( _data ) ) ); + } + + +} + +#include "vibed.moc" + diff --git a/plugins/vibed/vibed.h b/plugins/vibed/vibed.h new file mode 100644 index 000000000..357f0a92e --- /dev/null +++ b/plugins/vibed/vibed.h @@ -0,0 +1,100 @@ +/* vibed_strings.h - + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#ifndef _VIBED_STRINGS_H +#define _VIBED_STRINGS_H + +#include + +#include "instrument.h" +#include "sample_buffer.h" +#include "graph.h" +#include "pixmap_button.h" +#include "buffer_allocator.h" +#include "led_checkbox.h" +#include "impulse_editor.h" +#include "lcd_spinbox.h" +#include "nine_button_selector.h" + +class knob; +class notePlayHandle; + + +class vibed : public instrument +{ + Q_OBJECT + +public: + vibed( instrumentTrack * _channel_track ); + virtual ~vibed(); + + 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; + +public slots: + void showString( Uint8 _string ); + void contextMenuEvent( QContextMenuEvent * ); + void displayHelp( void ); + +private: + QPtrList m_pickKnobs; + QPtrList m_pickupKnobs; + QPtrList m_stiffnessKnobs; + QPtrList m_volumeKnobs; + QPtrList m_panKnobs; + QPtrList m_detuneKnobs; + QPtrList m_randomKnobs; + QPtrList m_lengthKnobs; + QPtrList m_editors; + QPtrList m_impulses; + QPtrList m_harmonics; + + knob * m_pickKnob; + knob * m_pickupKnob; + knob * m_stiffnessKnob; + knob * m_volumeKnob; + knob * m_panKnob; + knob * m_detuneKnob; + knob * m_randomKnob; + knob * m_lengthKnob; + impulseEditor * m_editor; + + nineButtonSelector * m_stringSelector; + nineButtonSelector * m_harmonic; + + ledCheckBox * m_impulse; + + sampleBuffer * m_sampleBuffer; + + int m_sampleLength; + +} ; + + +#endif diff --git a/plugins/vibed/vibrating_string.cpp b/plugins/vibed/vibrating_string.cpp new file mode 100644 index 000000000..c68d27483 --- /dev/null +++ b/plugins/vibed/vibrating_string.cpp @@ -0,0 +1,158 @@ +/* + * vibrating_sring.h - model of a vibrating string lifted from pluckedSynth + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#include + +#include "vibrating_string.h" +#include "templates.h" +#include "interpolation.h" + + +vibratingString::vibratingString( float _pitch, + float _pick, + float _pickup, + float * _impulse, + Uint32 _len, + sample_rate_t _sample_rate, + Uint8 _oversample, + float _randomize, + float _string_loss, + float _detune, + bool _state ): + m_oversample( _oversample ), + m_randomize( _randomize ), + m_stringLoss( 1.0f - _string_loss ), + m_state( 0.1f ) +{ + int string_length; + + string_length = static_cast( m_oversample *_sample_rate / + _pitch ) + 1; + string_length += static_cast( string_length * -_detune ); + + int pick = static_cast( ceil( string_length * _pick ) ); + + if( not _state ) + { + m_impulse = bufferAllocator::alloc( string_length ); + resample( _impulse, _len, string_length ); + } + else + { + m_impulse = bufferAllocator::alloc( _len ); + for( Uint32 i = 0; i < _len; i++ ) + { + m_impulse[i] = _impulse[i]; + } + } + + m_toBridge = vibratingString::initDelayLine( string_length, pick ); + m_fromBridge = vibratingString::initDelayLine( string_length, pick ); + + + vibratingString::setDelayLine( m_toBridge, pick, + m_impulse, _len, 0.5f, + _state ); + vibratingString::setDelayLine( m_fromBridge, pick, + m_impulse, _len, 0.5f, + _state); + + m_choice = static_cast( m_oversample * + static_cast( rand() ) / RAND_MAX ); + + m_pickupLoc = static_cast( _pickup * string_length ); +} + + + + +vibratingString::delayLine * FASTCALL vibratingString::initDelayLine( + int _len, + int _pick ) +{ + delayLine * dl = new vibratingString::delayLine[_len]; + dl->length = _len; + if( _len > 0 ) + { + dl->data = new sample_t[_len]; + float r; + float offset = 0.0f; + for( int i = 0; i < dl->length; i++ ) + { + r = static_cast( rand() ) / + RAND_MAX; + offset = ( m_randomize / 2.0f - + m_randomize ) * r; + dl->data[i] = offset; + } + } + else + { + dl->data = NULL; + } + + dl->pointer = dl->data; + dl->end = dl->data + _len - 1; + + return( dl ); +} + + + + +void FASTCALL vibratingString::freeDelayLine( delayLine * _dl ) +{ + if( _dl && _dl->data ) + { + delete[] _dl->data; + } + + _dl->data = NULL; + delete[] _dl; +} + + + + +void FASTCALL vibratingString::resample( float *_src, + f_cnt_t _src_frames, + f_cnt_t _dst_frames ) +{ + for( f_cnt_t frame = 0; frame < _dst_frames; ++frame ) + { + const float src_frame_float = frame * + (float) _src_frames / + _dst_frames; + const float frac_pos = src_frame_float - + static_cast( src_frame_float ); + const f_cnt_t src_frame = tLimit( + static_cast( src_frame_float ), + 1, _src_frames - 3 ); + m_impulse[frame] = cubicInterpolate( + _src[src_frame - 1], + _src[src_frame + 0], + _src[src_frame + 1], + _src[src_frame + 2], + frac_pos ); + } +} diff --git a/plugins/vibed/vibrating_string.h b/plugins/vibed/vibrating_string.h new file mode 100644 index 000000000..74e974a91 --- /dev/null +++ b/plugins/vibed/vibrating_string.h @@ -0,0 +1,272 @@ +/* + * vibrating_string.h - model of a vibrating string lifted from pluckedSynth + * + * Copyright (c) 2006 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#ifndef _VIBRATING_STRING_H +#define _VIBRATING_STRING_H + +#include +#include + +#include "config.h" +#include "types.h" +#include "buffer_allocator.h" + +class vibratingString +{ +public: + vibratingString( float _pitch, + float _pick, + float _pickup, + float * impluse, + Uint32 _len, + sample_rate_t _sample_rate, + Uint8 _oversample, + float _randomize, + float _string_loss, + float _detune, + bool _state ); + + inline ~vibratingString( void ) + { + bufferAllocator::free( m_impulse ); + vibratingString::freeDelayLine( m_fromBridge ); + vibratingString::freeDelayLine( m_toBridge ); + } + + inline sample_t nextSample( void ) + { + sample_t outsamp[m_oversample]; + sample_t ym0; + sample_t ypM; + for( Uint8 i = 0; i < m_oversample; i++) + { + // Output at pickup position + outsamp[i] = fromBridgeAccess( m_fromBridge, + m_pickupLoc ); + outsamp[i] += toBridgeAccess( m_toBridge, + m_pickupLoc ); + + // Sample traveling into "bridge" + ym0 = toBridgeAccess( m_toBridge, 1 ); + // Sample to "nut" + ypM = fromBridgeAccess( m_fromBridge, + m_fromBridge->length - 2 ); + + // String state update + + // Decrement pointer and then update + fromBridgeUpdate( m_fromBridge, + -bridgeReflection( ym0 ) ); + // Update and then increment pointer + toBridgeUpdate( m_toBridge, -ypM ); + } + return( outsamp[m_choice] ); + } + +private: + struct delayLine + { + sample_t * data; + int length; + sample_t * pointer; + sample_t * end; + } ; + + delayLine * m_fromBridge; + delayLine * m_toBridge; + int m_pickupLoc; + Uint8 m_oversample; + float m_randomize; + float m_stringLoss; + + float * m_impulse; + int m_choice; + float m_state; + + delayLine * FASTCALL initDelayLine( int _len, int _pick ); + static void FASTCALL freeDelayLine( delayLine * _dl ); + void FASTCALL resample( float *_src, + sample_rate_t _src_frames, + sample_rate_t _dst_frames ); + + /* setDelayLine initializes the string with an impulse at the pick + * position unless the impulse is longer than the string, in which + * case the impulse gets truncated. */ + inline void setDelayLine( delayLine * _dl, + int _pick, + const float * _values, + int _len, + float _scale, + bool _state ) + { + float r; + float offset; + + if( not _state ) + { + for( int i = 0; i < _pick; i++ ) + { + r = static_cast( rand() ) / + RAND_MAX; + offset = ( m_randomize / 2.0f - + m_randomize ) * r; + _dl->data[i] = _scale * + _values[_dl->length - i] + + offset; + } + for( int i = _pick; i < _dl->length; i++ ) + { + r = static_cast( rand() ) / + RAND_MAX; + offset = ( m_randomize / 2.0f - + m_randomize ) * r; + _dl->data[i] = _scale * + _values[i - _pick] + offset ; + } + } + else + { + if( _len + _pick > _dl->length ) + { + for( int i = _pick; i < _dl->length; i++ ) + { + r = static_cast( rand() ) / + RAND_MAX; + offset = ( m_randomize / 2.0f - + m_randomize ) * r; + _dl->data[i] = _scale * + _values[i-_pick] + + offset; + } + } + else + { + for( int i = 0; i < _len; i++ ) + { + r = static_cast( rand() ) / + RAND_MAX; + offset = ( m_randomize / 2.0f - + m_randomize ) * r; + _dl->data[i+_pick] = _scale * + _values[i] + + offset; + } + } + } + } + + /* toBridgeUpdate(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. */ + inline void toBridgeUpdate( delayLine * _dl, sample_t _insamp ) + { + register sample_t * ptr = _dl->pointer; + *ptr = _insamp * m_stringLoss; + ++ptr; + if( ptr > _dl->end ) + { + ptr = _dl->data; + } + _dl->pointer = ptr; + } + + /* fromBridgeUpdate(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. */ + inline void fromBridgeUpdate( delayLine * _dl, + sample_t _insamp ) + { + register sample_t * ptr = _dl->pointer; + --ptr; + if( ptr < _dl->data ) + { + ptr = _dl->end; + } + *ptr = _insamp * m_stringLoss; + _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 sample_t dlAccess( delayLine * _dl, int _position ) + { + sample_t * 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) + */ + + /* fromBridgeAccess(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 sample_t fromBridgeAccess( delayLine * _dl, + int _position ) + { + return( dlAccess( _dl, _position ) ); + } + + /* toBridgeAccess(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 sample_t toBridgeAccess( delayLine * _dl, int _position ) + { + return( dlAccess( _dl, _position ) ); + } + + inline sample_t bridgeReflection( sample_t _insamp ) + { + return( m_state = ( m_state + _insamp ) * 0.5 ); + } + +} ; + +#endif diff --git a/plugins/vibed/wavegraph4.png b/plugins/vibed/wavegraph4.png new file mode 100644 index 0000000000000000000000000000000000000000..07dbd91a9641f331f6507d287d7006785bb1710b GIT binary patch literal 10636 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 literal 0 HcmV?d00001 diff --git a/src/core/arp_and_chords_tab_widget.cpp b/src/core/arp_and_chords_tab_widget.cpp index 2a30cb007..9864c5ce5 100644 --- a/src/core/arp_and_chords_tab_widget.cpp +++ b/src/core/arp_and_chords_tab_widget.cpp @@ -472,9 +472,10 @@ void arpAndChordsTabWidget::processNote( notePlayHandle * _n ) // now follows code for arpeggio - if( _n->baseNote() == FALSE || m_arpDirectionBtnGrp->value() == OFF || - !m_arpGroupBox->isActive() || - ( _n->released() && _n->releaseFramesDone() >= + if( _n->baseNote() == FALSE || + ( m_arpDirectionBtnGrp->value() + 1) == OFF || + !m_arpGroupBox->isActive() || + ( _n->released() && _n->releaseFramesDone() >= _n->actualReleaseFramesToDo() ) ) { return; @@ -483,13 +484,13 @@ void arpAndChordsTabWidget::processNote( notePlayHandle * _n ) const int selected_arp = m_arpComboBox->value(); - constNotePlayHandleVector cnphv = notePlayHandle::nphsOfChannelTrack( - _n->getInstrumentTrack() ); + constNotePlayHandleVector cnphv = notePlayHandle::nphsOfInstrumentTrack( + _n->getInstrumentTrack() ); if( m_arpModeComboBox->value() != FREE && cnphv.size() == 0 ) { // maybe we're playing only a preset-preview-note? - cnphv = presetPreviewPlayHandle::nphsOfChannelTrack( - _n->getInstrumentTrack() ); + cnphv = presetPreviewPlayHandle::nphsOfInstrumentTrack( + _n->getInstrumentTrack() ); if( cnphv.size() == 0 ) { // still nothing found here, so lets return @@ -654,7 +655,7 @@ void arpAndChordsTabWidget::saveSettings( QDomDocument & _doc, _this.setAttribute( "arprange", m_arpRangeKnob->value() ); _this.setAttribute( "arptime", m_arpTimeKnob->value() ); _this.setAttribute( "arpgate", m_arpGateKnob->value() ); - _this.setAttribute( "arpdir", m_arpDirectionBtnGrp->value() ); + _this.setAttribute( "arpdir", m_arpDirectionBtnGrp->value() + 1 ); _this.setAttribute( "arpsyncmode", ( int ) m_arpTimeKnob->getSyncMode() ); @@ -675,14 +676,14 @@ void arpAndChordsTabWidget::loadSettings( const QDomElement & _this ) m_arpTimeKnob->setValue( _this.attribute( "arptime" ).toFloat() ); m_arpGateKnob->setValue( _this.attribute( "arpgate" ).toFloat() ); m_arpDirectionBtnGrp->setInitValue( - _this.attribute( "arpdir" ).toInt() ); + _this.attribute( "arpdir" ).toInt() - 1 ); m_arpTimeKnob->setSyncMode( ( tempoSyncKnob::tempoSyncMode ) _this.attribute( "arpsyncmode" ).toInt() ); m_arpModeComboBox->setValue( _this.attribute( "arpmode" ).toInt() ); - m_arpGroupBox->setState( m_arpDirectionBtnGrp->value() != OFF && + m_arpGroupBox->setState( _this.attribute( "arpdir" ).toInt() != OFF && !_this.attribute( "arpdisabled" ).toInt() ); } diff --git a/src/core/import_filter.cpp b/src/core/import_filter.cpp index e72bab62b..ddf3c3e7a 100644 --- a/src/core/import_filter.cpp +++ b/src/core/import_filter.cpp @@ -27,6 +27,7 @@ #include "import_filter.h" #include "track_container.h" +#include "project_journal.h" #ifdef QT4 @@ -75,6 +76,10 @@ void importFilter::import( const QString & _file_to_import, #endif ); + // do not record changes while importing files + const bool j = _tc->eng()->getProjectJournal()->isJournalling(); + _tc->eng()->getProjectJournal()->setJournalling( FALSE ); + for( vvector::iterator it = d.begin(); it != d.end(); ++it ) { @@ -93,6 +98,8 @@ void importFilter::import( const QString & _file_to_import, } } + _tc->eng()->getProjectJournal()->setJournalling( j ); + delete[] s; if( successful == FALSE ) diff --git a/src/core/note_play_handle.cpp b/src/core/note_play_handle.cpp index 8a2ad2c8e..11ccdbbf3 100644 --- a/src/core/note_play_handle.cpp +++ b/src/core/note_play_handle.cpp @@ -348,7 +348,7 @@ int notePlayHandle::index( void ) const -constNotePlayHandleVector notePlayHandle::nphsOfChannelTrack( +constNotePlayHandleVector notePlayHandle::nphsOfInstrumentTrack( const instrumentTrack * _it ) { const playHandleVector & phv = _it->eng()->getMixer()->playHandles(); diff --git a/src/core/preset_preview_play_handle.cpp b/src/core/preset_preview_play_handle.cpp index 10a9c67cc..178fa725e 100644 --- a/src/core/preset_preview_play_handle.cpp +++ b/src/core/preset_preview_play_handle.cpp @@ -56,12 +56,15 @@ class previewTrackContainer : public trackContainer public: previewTrackContainer( engine * _engine ) : trackContainer( _engine ), - m_previewChannelTrack( dynamic_cast( - track::create( track::CHANNEL_TRACK, - this ) )), + m_previewInstrumentTrack( NULL ), m_previewNote( NULL ), m_dataMutex() { + setJournalling( FALSE ); + m_previewInstrumentTrack = dynamic_cast( + track::create( track::CHANNEL_TRACK, + this ) ); + m_previewInstrumentTrack->setJournalling( FALSE ); hide(); } @@ -81,9 +84,9 @@ public: return( "previewtc" ); } - instrumentTrack * previewChannelTrack( void ) + instrumentTrack * previewInstrumentTrack( void ) { - return( m_previewChannelTrack ); + return( m_previewInstrumentTrack ); } notePlayHandle * previewNote( void ) @@ -108,7 +111,7 @@ public: private: - instrumentTrack * m_previewChannelTrack; + instrumentTrack * m_previewInstrumentTrack; notePlayHandle * m_previewNote; QMutex m_dataMutex; @@ -141,21 +144,21 @@ presetPreviewPlayHandle::presetPreviewPlayHandle( multimediaProject mmp( _preset_file ); - previewTC()->previewChannelTrack()->loadTrackSpecificSettings( + printf("load track sp\n"); + previewTC()->previewInstrumentTrack()->loadTrackSpecificSettings( mmp.content().firstChild().toElement() ); + printf("here\n"); // make sure, our preset-preview-track does not appear in any MIDI- // devices list, so just disable receiving/sending MIDI-events at all - previewTC()->previewChannelTrack()->m_midiPort->setMode( + previewTC()->previewInstrumentTrack()->m_midiPort->setMode( midiPort::DUMMY ); - // create temporary note - note n(); // create note-play-handle for it - m_previewNote = new notePlayHandle( previewTC()->previewChannelTrack(), - 0, ~0, + m_previewNote = new notePlayHandle( + previewTC()->previewInstrumentTrack(), 0, ~0, note( NULL, 0, 0, static_cast( A ), - static_cast( DEFAULT_OCTAVE-1 ), 100 ) ); + static_cast( DEFAULT_OCTAVE - 1 ), 100 ) ); previewTC()->setPreviewNote( m_previewNote ); @@ -210,7 +213,7 @@ void presetPreviewPlayHandle::cleanUp( engine * _engine ) -constNotePlayHandleVector presetPreviewPlayHandle::nphsOfChannelTrack( +constNotePlayHandleVector presetPreviewPlayHandle::nphsOfInstrumentTrack( const instrumentTrack * _it ) { constNotePlayHandleVector cnphv; diff --git a/src/core/song_editor.cpp b/src/core/song_editor.cpp index 537a661f1..71f34729a 100644 --- a/src/core/song_editor.cpp +++ b/src/core/song_editor.cpp @@ -1368,7 +1368,8 @@ void songEditor::clearProject( void ) eng()->getProjectNotes()->clear(); - eng()->getProjectJournal()->clear(); + eng()->getProjectJournal()->clearInvalidJournallingObjects(); + eng()->getProjectJournal()->clearJournal(); eng()->getProjectJournal()->setJournalling( TRUE ); } diff --git a/src/core/track.cpp b/src/core/track.cpp index adba617d4..9db270d75 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -595,7 +595,7 @@ trackContentWidget::~trackContentWidget() -trackContentObject * FASTCALL trackContentWidget::getTCO( csize _tco_num ) +trackContentObject * trackContentWidget::getTCO( csize _tco_num ) { if( _tco_num < m_trackContentObjects.size() ) { @@ -618,8 +618,7 @@ csize trackContentWidget::numOfTCOs( void ) -trackContentObject * FASTCALL trackContentWidget::addTCO( - trackContentObject * _tco ) +trackContentObject * trackContentWidget::addTCO( trackContentObject * _tco ) { QMap map; map["id"] = _tco->id(); @@ -639,7 +638,7 @@ trackContentObject * FASTCALL trackContentWidget::addTCO( -void FASTCALL trackContentWidget::removeTCO( csize _tco_num, bool _also_delete ) +void trackContentWidget::removeTCO( csize _tco_num, bool _also_delete ) { removeTCO( getTCO( _tco_num ), _also_delete ); } @@ -661,10 +660,12 @@ void trackContentWidget::removeTCO( trackContentObject * _tco, map["id"] = _tco->id(); map["state"] = mmp.toString(); addJournalEntry( journalEntry( REMOVE_TCO, map ) ); + if( _also_delete ) { delete _tco; } + m_trackContentObjects.erase( it ); getTrack()->eng()->getSongEditor()->setModified(); } @@ -873,15 +874,16 @@ void trackContentWidget::undoStep( journalEntry & _je ) case ADD_TCO: { QMap map = _je.data().toMap(); - journallingObject * jo = - eng()->getProjectJournal()->getJournallingObject( map["id"].toInt() ); - assert( jo != NULL ); + trackContentObject * tco = +dynamic_cast( + eng()->getProjectJournal()->getJournallingObject( map["id"].toInt() ) ); + assert( tco != NULL ); multimediaProject mmp( multimediaProject::JOURNAL_DATA ); - jo->saveState( mmp, mmp.content() ); + tco->saveState( mmp, mmp.content() ); map["state"] = mmp.toString(); _je.data() = map; - delete jo; + tco->close(); break; } @@ -1141,6 +1143,7 @@ void trackOperationsWidget::muteBtnRightClicked( void ) trackWidget::trackWidget( track * _track, QWidget * _parent ) : QWidget( _parent ), + journallingObject( _track->eng() ), m_track( _track ), m_trackOperationsWidget( this ), m_trackSettingsWidget( this ), @@ -1232,6 +1235,46 @@ void trackWidget::changePosition( const midiTime & _new_pos ) +void trackWidget::undoStep( journalEntry & _je ) +{ + saveJournallingState( FALSE ); + switch( _je.actionID() ) + { + case MOVE_TRACK: + { + trackContainer * tc = m_track->getTrackContainer(); + if( _je.data().toInt() > 0 ) + { + tc->moveTrackUp( m_track ); + } + else + { + tc->moveTrackDown( m_track ); + } + break; + } + case RESIZE_TRACK: + setFixedHeight( tMax( height() + + _je.data().toInt(), + MINIMAL_TRACK_HEIGHT ) ); + m_track->getTrackContainer()->realignTracks(); + break; + } + restoreJournallingState(); +} + + + + +void trackWidget::redoStep( journalEntry & _je ) +{ + journalEntry je( _je.actionID(), -_je.data().toInt() ); + undoStep( je ); +} + + + + void trackWidget::dragEnterEvent( QDragEnterEvent * _dee ) { stringPairDrag::processDragEnterEvent( _dee, "track_" + @@ -1320,6 +1363,7 @@ void trackWidget::mouseMoveEvent( QMouseEvent * _me ) { tc->moveTrackDown( m_track ); } + addJournalEntry( journalEntry( MOVE_TRACK, _me->y() ) ); } } else if( m_action == RESIZE_TRACK ) @@ -1429,7 +1473,7 @@ track::~track() -track * FASTCALL track::create( trackTypes _tt, trackContainer * _tc ) +track * track::create( trackTypes _tt, trackContainer * _tc ) { // while adding track, pause mixer for not getting into any trouble // because of track being not created completely so far @@ -1460,8 +1504,7 @@ track * FASTCALL track::create( trackTypes _tt, trackContainer * _tc ) -track * FASTCALL track::create( const QDomElement & _this, - trackContainer * _tc ) +track * track::create( const QDomElement & _this, trackContainer * _tc ) { track * t = create( static_cast( _this.attribute( "type" ).toInt() ), _tc ); @@ -1472,7 +1515,7 @@ track * FASTCALL track::create( const QDomElement & _this, -track * FASTCALL track::clone( track * _track ) +track * track::clone( track * _track ) { QDomDocument doc; QDomElement parent = doc.createElement( "clone" ); @@ -1492,7 +1535,7 @@ tact track::length( void ) const -void FASTCALL track::saveSettings( QDomDocument & _doc, QDomElement & _this ) +void track::saveSettings( QDomDocument & _doc, QDomElement & _this ) { csize num_of_tcos = getTrackContentWidget()->numOfTCOs(); @@ -1518,7 +1561,7 @@ void FASTCALL track::saveSettings( QDomDocument & _doc, QDomElement & _this ) -void FASTCALL track::loadSettings( const QDomElement & _this ) +void track::loadSettings( const QDomElement & _this ) { if( _this.attribute( "type" ).toInt() != type() ) { @@ -1550,7 +1593,11 @@ void FASTCALL track::loadSettings( const QDomElement & _this ) trackContentObject * tco = createTCO( midiTime( 0 ) ); tco->restoreState( node.toElement() ); + getTrackContentWidget()->saveJournallingState( + FALSE ); addTCO( tco ); + getTrackContentWidget()-> + restoreJournallingState(); } } node = node.nextSibling(); @@ -1566,7 +1613,7 @@ void FASTCALL track::loadSettings( const QDomElement & _this ) -trackContentObject * FASTCALL track::addTCO( trackContentObject * _tco ) +trackContentObject * track::addTCO( trackContentObject * _tco ) { return( getTrackContentWidget()->addTCO( _tco ) ); } @@ -1574,7 +1621,7 @@ trackContentObject * FASTCALL track::addTCO( trackContentObject * _tco ) -void FASTCALL track::removeTCO( csize _tco_num ) +void track::removeTCO( csize _tco_num ) { getTrackContentWidget()->removeTCO( _tco_num ); } @@ -1590,7 +1637,7 @@ csize track::numOfTCOs( void ) -trackContentObject * FASTCALL track::getTCO( csize _tco_num ) +trackContentObject * track::getTCO( csize _tco_num ) { return( getTrackContentWidget()->getTCO( _tco_num ) ); @@ -1599,7 +1646,7 @@ trackContentObject * FASTCALL track::getTCO( csize _tco_num ) -csize FASTCALL track::getTCONum( trackContentObject * _tco ) +csize track::getTCONum( trackContentObject * _tco ) { for( csize i = 0; i < getTrackContentWidget()->numOfTCOs(); ++i ) { @@ -1608,16 +1655,14 @@ csize FASTCALL track::getTCONum( trackContentObject * _tco ) return( i ); } } -#ifdef LMMS_DEBUG - qFatal( "track::getTCONum(...) -> _tco not found!\n" ); -#endif + qWarning( "track::getTCONum(...) -> _tco not found!\n" ); return( 0 ); } -void FASTCALL track::getTCOsInRange( vlist & _tco_v, +void track::getTCOsInRange( vlist & _tco_v, const midiTime & _start, const midiTime & _end ) { @@ -1655,7 +1700,7 @@ void FASTCALL track::getTCOsInRange( vlist & _tco_v, -void FASTCALL track::swapPositionOfTCOs( csize _tco_num1, csize _tco_num2 ) +void track::swapPositionOfTCOs( csize _tco_num1, csize _tco_num2 ) { getTrackContentWidget()->swapPositionOfTCOs( _tco_num1, _tco_num2 ); } diff --git a/src/core/track_container.cpp b/src/core/track_container.cpp index 2e05058a9..543d8cdb0 100644 --- a/src/core/track_container.cpp +++ b/src/core/track_container.cpp @@ -61,6 +61,7 @@ #include "import_filter.h" #include "instrument.h" #include "rubberband.h" +#include "project_journal.h" @@ -202,6 +203,10 @@ void trackContainer::cloneTrack( track * _track ) void trackContainer::addTrack( track * _track ) { + QMap map; + map["id"] = _track->id(); + addJournalEntry( journalEntry( ADD_TRACK, map ) ); + m_trackWidgets.push_back( _track->getTrackWidget() ); #ifndef QT4 m_scrollArea->addChild( _track->getTrackWidget() ); @@ -221,6 +226,13 @@ void trackContainer::removeTrack( track * _track ) m_trackWidgets.end(), _track->getTrackWidget() ); if( it != m_trackWidgets.end() ) { + QMap map; + multimediaProject mmp( multimediaProject::JOURNAL_DATA ); + _track->saveState( mmp, mmp.content() ); + map["id"] = _track->id(); + map["state"] = mmp.toString(); + addJournalEntry( journalEntry( REMOVE_TRACK, map ) ); + eng()->getMixer()->pause(); #ifndef QT4 m_scrollArea->removeChild( _track->getTrackWidget() ); @@ -417,6 +429,60 @@ void trackContainer::setPixelsPerTact( Uint16 _ppt ) +void trackContainer::undoStep( journalEntry & _je ) +{ + saveJournallingState( FALSE ); + switch( _je.actionID() ) + { + case ADD_TRACK: + { + QMap map = _je.data().toMap(); + track * tr = +dynamic_cast( + eng()->getProjectJournal()->getJournallingObject( map["id"].toInt() ) ); + assert( tr != NULL ); + multimediaProject mmp( + multimediaProject::JOURNAL_DATA ); + tr->saveState( mmp, mmp.content() ); + map["state"] = mmp.toString(); + _je.data() = map; + removeTrack( tr ); + break; + } + + case REMOVE_TRACK: + { + multimediaProject mmp( + _je.data().toMap()["state"].toString(), FALSE ); + track::create( mmp.content().firstChild().toElement(), + this ); + break; + } + } + restoreJournallingState(); +} + + + + +void trackContainer::redoStep( journalEntry & _je ) +{ + switch( _je.actionID() ) + { + case ADD_TRACK: + case REMOVE_TRACK: + _je.actionID() = ( _je.actionID() == ADD_TRACK ) ? + REMOVE_TRACK : ADD_TRACK; + undoStep( _je ); + _je.actionID() = ( _je.actionID() == ADD_TRACK ) ? + REMOVE_TRACK : ADD_TRACK; + break; + } +} + + + + void trackContainer::dragEnterEvent( QDragEnterEvent * _dee ) { stringPairDrag::processDragEnterEvent( _dee, diff --git a/src/lib/journalling_object.cpp b/src/lib/journalling_object.cpp index da0e667a1..37944bd60 100644 --- a/src/lib/journalling_object.cpp +++ b/src/lib/journalling_object.cpp @@ -69,6 +69,7 @@ journallingObject::~journallingObject() void journallingObject::undo( void ) { + printf("undo: %d\n", id() ); if( m_journalEntries.empty() == TRUE ) { return; @@ -85,6 +86,7 @@ void journallingObject::undo( void ) void journallingObject::redo( void ) { + printf("undo: %d\n", id() ); if( m_journalEntries.empty() == TRUE ) { return; @@ -103,9 +105,9 @@ QDomElement journallingObject::saveState( QDomDocument & _doc, QDomElement & _parent ) { QDomElement _this = _doc.createElement( nodeName() ); + _parent.appendChild( _this ); saveSettings( _doc, _this ); saveJournal( _doc, _this ); - _parent.appendChild( _this ); return( _this ); } @@ -115,7 +117,11 @@ QDomElement journallingObject::saveState( QDomDocument & _doc, void journallingObject::restoreState( const QDomElement & _this ) { saveJournallingState( FALSE ); + + // load actual settings loadSettings( _this ); + + // search for journal-node QDomNode node = _this.firstChild(); while( !node.isNull() ) { @@ -125,13 +131,14 @@ void journallingObject::restoreState( const QDomElement & _this ) } node = node.nextSibling(); } + restoreJournallingState(); } -void journallingObject::addJournalEntry( const journalEntry & _edit_step ) +void journallingObject::addJournalEntry( const journalEntry & _je ) { if( !( eng() == NULL || eng()->getProjectJournal()->isJournalling() == FALSE || @@ -139,7 +146,7 @@ void journallingObject::addJournalEntry( const journalEntry & _edit_step ) { m_journalEntries.erase( m_currentJournalEntry, m_journalEntries.end() ); - m_journalEntries.push_back( _edit_step ); + m_journalEntries.push_back( _je ); m_currentJournalEntry = m_journalEntries.end(); eng()->getProjectJournal()->journalEntryAdded( id() ); } diff --git a/src/lib/mmp.cpp b/src/lib/mmp.cpp index 5f00332ad..e898e765f 100644 --- a/src/lib/mmp.cpp +++ b/src/lib/mmp.cpp @@ -152,10 +152,8 @@ multimediaProject::multimediaProject( const QString & _in_file_name, } } - QDomElement root = documentElement(); m_type = type( root.attribute( "type" ) ); - QDomNode node = root.firstChild(); while( !node.isNull() ) { @@ -308,7 +306,10 @@ QString multimediaProject::typeName( projectTypes _project_type ) { if( _project_type >= UNKNOWN && _project_type < PROJ_TYPE_COUNT ) { - return( s_types[_project_type].m_name ); + return( s_types[_project_type].m_name +#warning compat-code, remove in 0.3.0 + .section( ',', 0, 0 ) + ); } return( s_types[UNKNOWN].m_name ); } diff --git a/src/lib/project_journal.cpp b/src/lib/project_journal.cpp index 6bed987bf..b1381f904 100644 --- a/src/lib/project_journal.cpp +++ b/src/lib/project_journal.cpp @@ -80,6 +80,7 @@ void projectJournal::redo( void ) journallingObject * jo; + printf("%d\n", m_joIDs[*(m_currentJournalEntry+1)] ); if( m_currentJournalEntry < m_journalEntries.end() && ( jo = m_joIDs[*m_currentJournalEntry++] ) != NULL ) { @@ -97,7 +98,7 @@ void projectJournal::journalEntryAdded( const jo_id_t _id ) m_journalEntries.push_back( _id ); m_currentJournalEntry = m_journalEntries.end(); eng()->getSongEditor()->setModified(); - printf("history size:%d\n", m_journalEntries.size()); + printf("history size: %d\n", m_journalEntries.size() ); } @@ -122,7 +123,7 @@ jo_id_t projectJournal::allocID( journallingObject * _obj ) void projectJournal::reallocID( const jo_id_t _id, journallingObject * _obj ) { - //printf("realloc %d %d\n", _id, _obj); + //printf("realloc %d %d\n", _id, _obj ); if( m_joIDs.contains( _id ) ) { m_joIDs[_id] = _obj; @@ -134,6 +135,7 @@ void projectJournal::reallocID( const jo_id_t _id, journallingObject * _obj ) void projectJournal::forgetAboutID( const jo_id_t _id ) { + printf("forget about %d\n", _id ); journalEntryVector::iterator it; while( ( it = qFind( m_journalEntries.begin(), m_journalEntries.end(), _id ) ) != m_journalEntries.end() ) @@ -150,12 +152,22 @@ void projectJournal::forgetAboutID( const jo_id_t _id ) -void projectJournal::clear( void ) +void projectJournal::clearInvalidJournallingObjects( void ) { - while( m_joIDs.size() ) + vlist::const_iterator it; + for( joIDMap::iterator it = m_joIDs.begin(); it != m_joIDs.end(); ) { - forgetAboutID( m_joIDs.keys().front() ); + if( it.data() == NULL ) + { + forgetAboutID( it.key() ); + it = m_joIDs.begin(); + } + else + { + ++it; + } } + //clearJournal(); } diff --git a/src/tracks/bb_track.cpp b/src/tracks/bb_track.cpp index a20868c26..a2b8e7153 100644 --- a/src/tracks/bb_track.cpp +++ b/src/tracks/bb_track.cpp @@ -357,7 +357,8 @@ bool FASTCALL bbTrack::play( const midiTime & _start, { if( _tco_num >= 0 ) { - return( eng()->getBBEditor()->play( _start, _start_frame, _frames, + return( eng()->getBBEditor()->play( _start, _start_frame, + _frames, _frame_base, s_infoMap[this] ) ); } @@ -424,7 +425,8 @@ void bbTrack::saveTrackSpecificSettings( QDomDocument & _doc, /* _this.setAttribute( "current", s_infoMap[this] == eng()->getBBEditor()->currentBB() );*/ if( s_infoMap[this] == 0 && - _this.parentNode().nodeName() != "clone" ) + _this.parentNode().nodeName() != "clone" && + _this.parentNode().nodeName() != "journaldata" ) { eng()->getBBEditor()->saveState( _doc, _this ); } diff --git a/src/tracks/instrument_track.cpp b/src/tracks/instrument_track.cpp index 56d3d8304..3e8343377 100644 --- a/src/tracks/instrument_track.cpp +++ b/src/tracks/instrument_track.cpp @@ -415,7 +415,9 @@ void instrumentTrack::saveSettingsBtnClicked( void ) { multimediaProject mmp( multimediaProject::INSTRUMENT_TRACK_SETTINGS ); - saveTrackSpecificSettings( mmp, mmp.content() ); + QDomElement _this = mmp.createElement( nodeName() ); + saveTrackSpecificSettings( mmp, _this ); + mmp.content().appendChild( _this ); #ifdef QT4 mmp.writeFile( sfd.selectedFiles()[0] ); #else diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index 1c47c6870..fb2bc0607 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -419,7 +419,7 @@ void pattern::saveSettings( QDomDocument & _doc, QDomElement & _this ) // pattern, we must not store actual position, instead we store -1 // which tells loadSettings() not to mess around with position if( _this.parentNode().nodeName() == "clipboard" || - _this.parentNode().nodeName() == "dnddata" ) + _this.parentNode().nodeName() == "dnddata" ) { _this.setAttribute( "pos", -1 ); }