diff --git a/AUTHORS b/AUTHORS index 9e534b45ff..845f39b9c6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,12 +1,15 @@ Tobias Doerffel - + Maintainer, main-development, artwork etc. Danny McRae - + development Sebastian Tilsch - + recording of many samples +gabriel + + additional artwork diff --git a/ChangeLog b/ChangeLog index f83f95224c..a27a61a2ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,280 @@ +2006-01-02 Tobias Doerffel + + * plugins/vestige/vestige.cpp: + set vestige-logo as window-icon of plugin-GUI-window + + * src/core/instrument.cpp: + set logo of plugin as window-icon of channel-track + + * include/dummy_instrument.h: + * include/dummy_plugin.h: + * include/instrument.h: + * include/plugin.h: + * src/core/instrument.cpp: + * src/core/plugin.cpp: + small changes in plugin-API: plugin now always has to pass pointer to + plugin-descriptor to plugin-dtor to make the latter one able to + provide several information + + * src/core/plugin.cpp: + search for plugin-libs in configManager::pluginDir() which is + $prefix/lib/lmms - hopefully solves problems with finding plugins on + some systems + + * include/channel_track.h: + * include/midi_tab_widget.h: + * src/core/midi_tab_widget.cpp: + * src/tracks/channel_track.cpp: + when using Raw-MIDI-client, make items "MIDI input/output" checkable + and enable/disable MIDI-input/output accordingly if user + checked/unchecked it and update check-state if user changed MIDI-mode + in midi-tab-widget in channel-track + + * src/core/midi_tab_widget.cpp: + set MIDI-output-channel to 1 per default + + * src/lib/sample_buffer.cpp: + added flac-files to filter of file-selection-dialog + + * include/note_play_handle.h: + * src/core/note_play_handle.cpp: + when invalidating note-play-handle, do some stuff which actually would + be done by dtor if m_channelTrack wouldn't be NULL + +2006-01-01 Tobias Doerffel + + * src/core/track.cpp: + added tooltip to track-op-widget telling the user something about + drag'n'drop-functionality... + + * include/lmms_main_win.h: + * src/core/lmms_main_win.cpp: + * src/lib/string_pair_drag.cpp: + if main-window looses focus or a drag is completed, clear + key-modifiers of LMMS-main-window, because we might have lost + key-release-events in these cases and therefore our modifier-state-map + could be incorrect - fixes several bugs concerning drag'n'drop + + * README: + * src/core/about_dialog.cpp: + extended copyright from 2005 to 2006 - Happy New Year! + +2005-12-31 Tobias Doerffel + + * include/channel_track.h: + * src/tracks/channel_track.cpp: + removed surround-area in track-settings-widget and added button with + MIDI-connection-menu instead + +2005-12-30 Tobias Doerffel + + * include/track.h: + * include/track_container.h: + * src/core/track.cpp: + * src/core/track_container.cpp: + revised all the things around track-operations: + - tracks are now directly movable via the grip at the beginning of a + track - replaces "move up/down"-buttons and is much more usable + - actions (clone/delete track) are now part of a popup-menu + + * src/core/lmms_main_win.cpp: + - corrected file-description at the beginning + - add space at left side before adding tool-buttons + + * src/core/midi_tab_widget.cpp: + use smaller font for connection-selection-menu + +2005-12-29 Tobias Doerffel + + * src/widgets/fade_button.cpp: + do not update() directly in nextState(), use QTimer instead for avoiding + xlib-threading-errors + +2005-12-28 Tobias Doerffel + + * plugins/vestige/communication.h: + * plugins/vestige/fstclient.cpp: + * plugins/vestige/fstclient.h: + * plugins/vestige/fstserver.cpp: + * plugins/vestige/vestige.cpp: + * plugins/vestige/vestige.h: + - support for telling plugin current BPM, also catches BPM-changes + - handle plugins without GUI correctly + + * include/tool_button.h: + * src/widgets/tool_button.cpp: + catch toggle-signals to emit clicked()-signal which is neccessary if a + button is checked using setChecked()-method and not by the user - + fixes some bugs with piano-roll + + * include/piano_roll.h: + * src/core/piano_roll.cpp: + - show text-float after user copied notes + - do not play note when just moving selection + - when update()ing paint everything in a pixmap which is painted in + paintEvent() - saves all the repaints everytime mouse-cursor is moved + and makes painting tool-cursor possible again + + * src/tracks/channel_track.cpp: + corrected calculation in channelTrack::masterKey() + +2005-12-27 Tobias Doerffel + + * include/piano_roll.h: + * src/core/piano_roll.cpp: + always reset cursor when receiving leave-event + + * include/channel_track.h: + * src/tracks/channel_track.cpp: + use new fade-button as MIDI-event-indicator as well as simple + play-default-tone-button + + * include/fade_button.h: + * src/widgets/fade_button.cpp: + added fade-button which can be activated and fades back to + default-color afterwards + + * src/core/arp_and_chords_tab_widget.cpp: + * src/core/envelope_and_lfo_widget.cpp: + * src/core/envelope_tab_widget.cpp: + * src/core/midi_tab_widget.cpp: + * src/core/note.cpp: + * src/core/song_editor.cpp: + * src/core/track.cpp: + * src/tracks/bb_track.cpp: + * src/tracks/channel_track.cpp: + * src/tracks/sample_track.cpp: + do not use QString::number() for saving scalar value with + setAttribute() as it is obsolete + + * src/audio/audio_alsa.cpp: + * src/audio/audio_oss.cpp: + start audio-thread with QThread::HightestPriority for having less xruns + + * src/tracks/pattern.cpp: + save m_steps-property, otherwise restoring it in loadSettings() makes + no sense... - fixes bug which caused LMMS to always reset number of + steps to 16 when loading files, even if the user created patterns + containing more than 16 steps + + * include/audio_dummy.h: + - fixed missing implementation of thread running the whole time and + calling audioDevice::processNextBuffer() -> fixes bugs & lockups when + using audio-dummy-driver + - thread now always waits the amount of time that is left for the + current buffer, so if rendering of current buffer went faster than + in realtime, the song doesn't play at a higher speed + +2005-12-26 Tobias Doerffel + + * plugins/vestige/vestige.cpp: + determine real key of note using channelTrack::masterKey + + * include/micro_timer.h: + moved micro-timer-class from mixer.cpp in separate header for being + available to all modules of LMMS + + * src/core/mixer.cpp: + added metronome-sounds when recording in piano-roll + + * src/lib/sample_buffer.cpp: + - added resample()-method for resampling whole sample-buffer + - after libsndfile try to load sample with libvorbis instead of + SDL_sound as the latter one seems to be buggy on few systems and + leads to unexpected crashes + - if sample-decoder doesn't resample sample automatically, do it + afterwards using resample() + + * src/core/track_container.cpp: + accept drops of type samplefile and sampledata too and create new + channel-track with AudioFileProcessor + + * plugins/audio_file_processor/audio_file_processor.cpp: + save/load sample-data which was dragged on plugin in settings + + * src/core/track.cpp: + display correct length and now additionally start- and end-position of + track-content-object + + * include/bb_track.h: + * src/tracks/bb_track.cpp: + do not align position and length of bb-track-objects on tact-boundaries + as it offers an interesting new feature (incomplete/start beats etc.!) + +2005-12-25 Tobias Doerffel + + * src/widgets/visualization_widget.cpp: + enable visualization-widget per default + + * plugins/vestige/vestige.cpp: + - do not crash when loading settings with empty plugin-attribute (e.g. + older projects/presets) + - set channel-name according to plugin-name + - added note-off-button for being able to note off hanging notes + (which sometimes occurs in combination with arpeggios) + +2005-12-24 Tobias Doerffel + + * plugins/vestige/vestige.cpp: + use new parameter-saving/loading-feature when saving/loading settings + + * plugins/vestige/communication.h: + * plugins/vestige/fstclient.cpp: + * plugins/vestige/fstclient.h: + * plugins/vestige/fstserver.cpp: + * plugins/vestige/fstserver.h: + * plugins/vestige/fstcore.c: + - added support for saving/loading parameters which almost completes + LMMS's rudimentary VST-support + - support for querying parameter-properties + - some changes in initialization of plugin + + * src/tracks/pattern.cpp: + pass unused wheel-events to trackContentObect for being able to scroll + within song-editor + +2005-12-23 Tobias Doerffel + + * plugins/vestige/fstcore.c: + a lot of clean-ups and other bug-fixes making VeSTige almost usable + and stable + + * plugins/vestige/fstclient.h: + * plugins/vestige/fstclient.cpp: + save PID of children when fork()ing XFST-server which is used for + sending SIGTERM when destroying everything + + * plugins/vestige/communication.h: + * plugins/vestige/fstclient.cpp: + * plugins/vestige/fstserver.cpp: + * plugins/vestige/fstcore.c: + do not show editor until client created x11-embed-widget - solves + problems with not-embedded plugins under KDE + + * plugins/vestige/fstserver.cpp: + rewrote MIDI-enqueueing-code as the old one was very buggy and + unreliable + + * plugins/vestige/vestige.h: + * plugins/vestige/vestige.cpp: + added mutex for plugin which solves some problems + + * include/mixer.h: + * src/core/mixer.cpp: + per default clear all play-handles but instrument-play-handles in + mixer::clear() as instrument-playhandles normally exist during the + whole life-time of a certain plugin and must not be deleted when just + stopping song etc. + + * include/play_handle.h: + added type-information, so every derived class has to pass a + type-constant to playHandle-constructor + +2005-12-22 Tobias Doerffel + + * configure.in: + made 0.1.2 release + 2005-12-21 Tobias Doerffel * src/lib/sample_buffer.cpp: diff --git a/Makefile.am b/Makefile.am index 7ed930f04a..6387f00876 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,6 +52,7 @@ lmms_MOC = \ ./envelope_and_lfo_widget.moc \ ./envelope_tab_widget.moc \ ./export_project_dialog.moc \ + ./fade_button.moc \ ./file_browser.moc \ ./group_box.moc \ ./kmultitabbar.moc \ @@ -84,6 +85,7 @@ lmms_MOC = \ ./tab_widget.moc \ ./tempo_sync_knob.moc \ ./timeline.moc \ + ./tool_button.moc \ ./track_container.moc \ ./track.moc \ ./visualization_widget.moc @@ -158,6 +160,7 @@ lmms_SOURCES = \ $(srcdir)/src/tracks/pattern.cpp \ $(srcdir)/src/tracks/sample_track.cpp \ $(srcdir)/src/widgets/cpuload_widget.cpp \ + $(srcdir)/src/widgets/fade_button.cpp \ $(srcdir)/src/widgets/group_box.cpp \ $(srcdir)/src/widgets/kmultitabbar.cpp \ $(srcdir)/src/widgets/knob.cpp \ @@ -276,6 +279,8 @@ lmms_SOURCES = \ $(srcdir)/include/tool_button.h \ $(srcdir)/include/cpuload_widget.h \ $(srcdir)/include/midi_alsa_seq.h \ + $(srcdir)/include/micro_timer.h \ + $(srcdir)/include/fade_button.h \ $(srcdir)/include/qxembed.h diff --git a/README b/README index 095c1d952e..fcffbdf397 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ Linux MultiMedia Studio 0.1.2 ============================== -Copyright (c) 2004-2005 by Tobias Doerffel and others. +Copyright (c) 2004-2006 by Tobias Doerffel and others. This program is free software; you can redistribute it and/or modify @@ -45,7 +45,7 @@ LMMS working on a pentium I with 60 MHz... ;-) Therefore you should have at least 500 MHz, but for really enjoying LMMS less than 1 GHz makes no sense... -Required libraries are: +Required libraries: - multithreaded version of Qt 3.0 (at least 3.2 recommended) or higher (tested up to 4.1.0) with devel-files diff --git a/TODO b/TODO index 64d90828b3..ff933cbbe0 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,12 @@ to be done as soon as possible: +- debug arpeggio with certain times (TB303-arp!) +- fix bug with recording on arpeggio-channel - do not skip samples because of rounding when resampling in src/lib/sample_buffer.cpp - MIDI-program/MIDI-mapping/process program-/channel-change-events from MIDI-files - do not allow to connect output-port of channel to own input-port! - add note-len- and note-alignment-selectbox to piano-roll - DSSI-support -- save/load parameters of VST-plugin - 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 - only redraw region given by paint-event in pattern, bbTCO, sampleTCO etc. @@ -17,7 +18,6 @@ to be done as soon as possible: - solve problems with different keyboard-layouts when playing channel-track with pc-keyboard -> use tr() - balance env+lfo - autosave every 1 minute -- audioDummy: always wait until the stuff normally would have been written (=simulate blocking IO) - plucked-string-synth: knob for metallic -> use noise as wave-shape - finish qt4-port and make LMMS usable when compiling with Qt4 - rewrite export-project-dialog using layout-mechanism diff --git a/configure.in b/configure.in index 2ac8ac2d1a..3d56e0004b 100644 --- a/configure.in +++ b/configure.in @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) -AC_INIT(lmms, 0.1.1-cvs20051221, tobydox/at/users.sourceforge.net) -AM_INIT_AUTOMAKE(lmms, 0.1.1-cvs20051221) +AC_INIT(lmms, 0.1.2-cvs20060102, tobydox/at/users.sourceforge.net) +AM_INIT_AUTOMAKE(lmms, 0.1.2-cvs20060102) AM_CONFIG_HEADER(config.h) @@ -22,7 +22,7 @@ gw_CHECK_QT # checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([fcntl.h memory.h string.h sys/ioctl.h unistd.h stdlib.h pthread.h sys/ipc.h sys/shm.h sys/time.h sys/select.h sys/types.h stdarg.h]) +AC_CHECK_HEADERS([fcntl.h memory.h string.h sys/ioctl.h unistd.h stdlib.h pthread.h sys/ipc.h sys/shm.h sys/time.h sys/select.h sys/types.h stdarg.h signal.h]) # checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/include/audio_dummy.h b/include/audio_dummy.h index 243894a518..63b355ec88 100644 --- a/include/audio_dummy.h +++ b/include/audio_dummy.h @@ -27,19 +27,22 @@ #define _AUDIO_DUMMY_H #include "audio_device.h" +#include "micro_timer.h" -class audioDummy : public audioDevice +class audioDummy : public audioDevice, public QThread { public: audioDummy( Uint32 _sample_rate, bool & _success_ful ) : - audioDevice( _sample_rate, DEFAULT_CHANNELS ) + audioDevice( _sample_rate, DEFAULT_CHANNELS ), + m_quit( FALSE ) { _success_ful = TRUE; } virtual ~audioDummy() { + stopProcessing(); } inline static QString name( void ) @@ -68,8 +71,43 @@ public: private: - // TODO: derive from QThread and call getNextBuffer() in an - // endless loop + virtual void startProcessing( void ) + { + start(); + } + + virtual void stopProcessing( void ) + { + if( isRunning() ) + { + m_quit = TRUE; + wait( 1000 ); + terminate(); + } + } + + virtual void run( void ) + { + microTimer timer; + while( m_quit == FALSE ) + { + timer.reset(); + processNextBuffer(); + const Sint32 microseconds = static_cast( + mixer::inst()->framesPerAudioBuffer() * + 1000000.0f / + mixer::inst()->sampleRate() - + timer.elapsed() ); + if( microseconds > 0 ) + { + usleep( microseconds ); + } + } + } + + + volatile bool m_quit; + } ; diff --git a/include/audio_jack.h b/include/audio_jack.h index a44c776aa3..6e2635e83f 100644 --- a/include/audio_jack.h +++ b/include/audio_jack.h @@ -72,7 +72,7 @@ public: inline static QString name( void ) { - return( setupWidget::tr( "JACK (Jack Audio Connection Kit)" ) ); + return( setupWidget::tr( "JACK (JACK Audio Connection Kit)" ) ); } diff --git a/include/bb_track.h b/include/bb_track.h index 0c1f85a232..31bb4eb35d 100644 --- a/include/bb_track.h +++ b/include/bb_track.h @@ -55,9 +55,6 @@ public: bbTCO( track * _track, const QColor & _c = QColor() ); virtual ~bbTCO(); - virtual void FASTCALL movePosition( const midiTime & _pos ); - virtual void FASTCALL changeLength( const midiTime & _length ); - virtual void FASTCALL saveSettings( QDomDocument & _doc, QDomElement & _parent ); virtual void FASTCALL loadSettings( const QDomElement & _this ); diff --git a/include/dummy_instrument.h b/include/dummy_instrument.h index 8c87e33689..c75ce62d14 100644 --- a/include/dummy_instrument.h +++ b/include/dummy_instrument.h @@ -2,7 +2,7 @@ * dummy_instrument.h - instrument used as fallback if an instrument couldn't * be loaded * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -34,7 +34,7 @@ class dummyInstrument : public instrument { public: inline dummyInstrument( channelTrack * _channel_track ) : - instrument( _channel_track, "Dummy instrument" ) + instrument( _channel_track, NULL ) { } diff --git a/include/dummy_plugin.h b/include/dummy_plugin.h index 819bee932c..c620c5efa9 100644 --- a/include/dummy_plugin.h +++ b/include/dummy_plugin.h @@ -1,8 +1,8 @@ /* - * dummy_plugin.h - empty plugin which is used as fallback if a plugin wasn't - * found + * dummy_plugin.h - empty plugin which is used as fallback if a plugin couldn't + * be found * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -34,7 +34,7 @@ class dummyPlugin : public plugin { public: inline dummyPlugin( void ) : - plugin( "Dummy plugin", plugin::UNDEFINED ) + plugin( NULL ) { } diff --git a/include/embed.h b/include/embed.h index f9f4088012..9a2f209b7f 100644 --- a/include/embed.h +++ b/include/embed.h @@ -1,7 +1,7 @@ /* * embed.h - misc. stuff for using embedded data (resources linked into binary) * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * diff --git a/include/fade_button.h b/include/fade_button.h new file mode 100644 index 0000000000..bd98c2f991 --- /dev/null +++ b/include/fade_button.h @@ -0,0 +1,77 @@ +/* + * fade_button.h - declaration of class fadeButton + * + * Copyright (c) 2005 Tobias Doerffel + * + * 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 _FADE_BUTTON_H +#define _FADE_BUTTON_H + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include + +#else + +#include +#include + +#endif + + + +class fadeButton : public QButton +{ + Q_OBJECT +public: + fadeButton( const QColor & _normal_color, const QColor & + _activated_color, QWidget * _parent ); + + virtual ~fadeButton(); + + +public slots: + void activate( void ); + void reset( void ); + + +protected: + virtual void paintEvent( QPaintEvent * _pe ); + + +private slots: + void nextState( void ); + + +private: + float m_state; + QColor m_normalColor; + QColor m_activatedColor; + +} ; + + +#endif + diff --git a/include/instrument.h b/include/instrument.h index 5813dc8140..ed5a2bbe89 100644 --- a/include/instrument.h +++ b/include/instrument.h @@ -2,7 +2,7 @@ * instrument.h - declaration of class instrument, which provides a * standard interface for all instrument plugins * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -60,7 +60,8 @@ class notePlayHandle; class instrument : public QWidget, public plugin { public: - instrument( channelTrack * _channel_track, const QString & _name ); + instrument( channelTrack * _channel_track, + const descriptor * _descriptor ); virtual ~instrument(); // if the plugin doesn't play each note, it can create an instrument- @@ -68,7 +69,7 @@ public: // output buffer only once per mixer-period virtual void play( void ); - // must be overloaded by actual plugin + // to be overloaded by actual plugin virtual void FASTCALL playNote( notePlayHandle * note_to_play ); // needed for deleting plugin-specific-data of a note - plugin has to diff --git a/include/instrument_play_handle.h b/include/instrument_play_handle.h index 5e7df39459..19c4e02793 100644 --- a/include/instrument_play_handle.h +++ b/include/instrument_play_handle.h @@ -34,7 +34,7 @@ class instrumentPlayHandle : public playHandle { public: inline instrumentPlayHandle( instrument * _instrument ) : - playHandle(), + playHandle( INSTRUMENT_PLAY_HANDLE ), m_instrument( _instrument ) { } diff --git a/include/micro_timer.h b/include/micro_timer.h new file mode 100644 index 0000000000..c4e25762bc --- /dev/null +++ b/include/micro_timer.h @@ -0,0 +1,70 @@ +/* + * micro_timer.h - simple high-precision timer + * + * Copyright (c) 2005 Tobias Doerffel + * + * 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 _MICRO_TIMER +#define _MICRO_TIMER + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + + +class microTimer +{ +public: + inline microTimer( void ) + { + reset(); + } + + inline ~microTimer() + { + } + + inline void reset( void ) + { + gettimeofday( &begin, NULL ); + } + + inline Uint32 elapsed( void ) const + { + struct timeval now; + gettimeofday( &now, NULL ); + return( ( now.tv_sec - begin.tv_sec ) * 1000 * 1000 + + ( now.tv_usec - begin.tv_usec ) ); + } + + +private: + struct timeval begin; + +} ; + + +#endif diff --git a/include/midi_port.h b/include/midi_port.h index a936194b6f..fe56e707be 100644 --- a/include/midi_port.h +++ b/include/midi_port.h @@ -81,7 +81,7 @@ public: return( m_mode ); } - void setMode( modes _mode ); + void FASTCALL setMode( modes _mode ); inline Sint8 inputChannel( void ) const { diff --git a/include/midi_tab_widget.h b/include/midi_tab_widget.h index 84ae0b6eee..2d9c4030b1 100644 --- a/include/midi_tab_widget.h +++ b/include/midi_tab_widget.h @@ -2,7 +2,7 @@ * midi_tab_widget.h - tab-widget in channel-track-window for setting up * MIDI-related stuff * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -74,11 +74,13 @@ public: } +public slots: + void midiPortModeToggled( bool = FALSE ); + protected slots: void inputChannelChanged( int ); void outputChannelChanged( int ); - void midiPortModeToggled( bool ); void readablePortsChanged( void ); void writeablePortsChanged( void ); void activatedReadablePort( QAction * _item ); @@ -99,7 +101,9 @@ private: QMenu * m_readablePorts; QMenu * m_writeablePorts; - + + friend class channelTrack; + } ; diff --git a/include/mixer.h b/include/mixer.h index d5719d407e..89ad76ee52 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -242,7 +242,7 @@ public: } - void clear( void ); + void FASTCALL clear( bool _everything = FALSE ); void FASTCALL clearAudioBuffer( sampleFrame * _ab, Uint32 _frames ); diff --git a/include/note_play_handle.h b/include/note_play_handle.h index 4ee5e46c41..5f45f44cc9 100644 --- a/include/note_play_handle.h +++ b/include/note_play_handle.h @@ -2,7 +2,7 @@ * note_play_handle.h - declaration of class notePlayHandle which is needed * by LMMS-Play-Engine * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -46,9 +46,9 @@ public: void * m_pluginData; basicFilters<> * m_filter; - notePlayHandle( channelTrack * _chnl_trk, Uint32 _frames_ahead, - Uint32 _frames, note * n, - bool _arp_note = FALSE ) FASTCALL; + notePlayHandle( channelTrack * _chnl_trk, const Uint32 _frames_ahead, + const Uint32 _frames, note * _n, + const bool _arp_note = FALSE ) FASTCALL; ~notePlayHandle(); diff --git a/include/piano_roll.h b/include/piano_roll.h index 1783c050c1..88c2feda97 100644 --- a/include/piano_roll.h +++ b/include/piano_roll.h @@ -33,11 +33,13 @@ #include #include +#include #else #include #include +#include #endif @@ -72,25 +74,38 @@ public: } void FASTCALL setCurrentPattern( pattern * _new_pattern ); + + inline bool isRecording( void ) const + { + return( m_recording ); + } + inline const pattern * currentPattern( void ) const { return( m_pattern ); } + inline bool validPattern( void ) const { return( m_pattern != NULL ); } +public slots: + virtual void update( void ); + + protected: - void closeEvent( QCloseEvent * _ce ); - void paintEvent( QPaintEvent * _pe ); - void resizeEvent( QResizeEvent * _re ); - void mousePressEvent( QMouseEvent * _me ); - void mouseReleaseEvent( QMouseEvent * _me ); - void mouseMoveEvent( QMouseEvent * _me ); - void keyPressEvent( QKeyEvent * _ke ); - void wheelEvent( QWheelEvent * _we ); + virtual void closeEvent( QCloseEvent * _ce ); + virtual void enterEvent( QEvent * _e ); + virtual void keyPressEvent( QKeyEvent * _ke ); + virtual void leaveEvent( QEvent * _e ); + virtual void mousePressEvent( QMouseEvent * _me ); + virtual void mouseReleaseEvent( QMouseEvent * _me ); + virtual void mouseMoveEvent( QMouseEvent * _me ); + virtual void paintEvent( QPaintEvent * _pe ); + virtual void resizeEvent( QResizeEvent * _re ); + virtual void wheelEvent( QWheelEvent * _we ); int FASTCALL getKey( int _y ); inline void drawNoteRect( QPainter & _p, Uint16 _x, Uint16 _y, @@ -154,6 +169,12 @@ private: } ; + pianoRoll( void ); + pianoRoll( const pianoRoll & ); + ~pianoRoll(); + + + static pianoRoll * s_instanceOfMe; static QPixmap * s_whiteKeyBigPm; @@ -184,6 +205,9 @@ private: QComboBox * m_zoomingComboBox; + QPixmap m_paintPixmap; + bool m_cursorInside; + pattern * m_pattern; QScrollBar * m_leftRightScroll; @@ -225,10 +249,6 @@ private: bool m_scrollBack; - pianoRoll( void ); - pianoRoll( const pianoRoll & ); - ~pianoRoll(); - friend class lmmsMainWin; diff --git a/include/play_handle.h b/include/play_handle.h index 99ac0e907e..8a6b05f445 100644 --- a/include/play_handle.h +++ b/include/play_handle.h @@ -47,12 +47,26 @@ class playHandle { public: - inline playHandle( void ) + enum types + { + NOTE_PLAY_HANDLE, INSTRUMENT_PLAY_HANDLE, SAMPLE_PLAY_HANDLE, + PRESET_PREVIEW_PLAY_HANDLE + } ; + + inline playHandle( types _type ) : + m_type( _type ) { } + virtual inline ~playHandle() { } + + inline types type( void ) const + { + return( m_type ); + } + virtual void play( void ) = 0; virtual bool done( void ) const = 0; @@ -67,6 +81,7 @@ public: private: + types m_type; } ; diff --git a/include/plugin.h b/include/plugin.h index 34ca1f06e9..a547c2a4ee 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -1,7 +1,7 @@ /* * plugin.h - class plugin, the base-class and generic interface for all plugins * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -85,21 +85,25 @@ public: } ; // contructor of a plugin - // _name: public name of plugin - // _type: one of the plugin-types defined above - plugin( const QString & _public_name, pluginTypes _type ); + plugin( const descriptor * _descriptor ); virtual ~plugin(); - // returns the name, the plugin passed to plugin-constructor - inline const QString & publicName( void ) const + // returns public-name out of descriptor + inline QString publicName( void ) const { - return( m_publicName ); + return( m_descriptor->public_name ); } - // return type + // return plugin-type inline pluginTypes type( void ) const { - return( m_type ); + return( m_descriptor->type ); + } + + // return plugin-descriptor for further information + inline const descriptor * getDescriptor( void ) const + { + return( m_descriptor ); } // plugins can overload this for making other classes able to change @@ -122,8 +126,7 @@ public: vvector & _plugin_descs ); private: - const QString m_publicName; - const pluginTypes m_type; + const descriptor * m_descriptor; // pointer to instantiation-function in plugin typedef plugin * ( * instantiationHook )( void * ); diff --git a/include/qt3support.h b/include/qt3support.h index 58b9e52204..2d61d3f04a 100644 --- a/include/qt3support.h +++ b/include/qt3support.h @@ -82,6 +82,7 @@ inline QString baseName( const QString & _file ) // QWidget #define setWindowTitle setCaption #define setWindowIcon setIcon +#define windowIcon icon #define isExplicitlyHidden isHidden #define accessibleName name #define ensurePolished constPolish @@ -116,6 +117,7 @@ inline QString baseName( const QString & _file ) // QAbstractButton/QButton #define setCheckable setToggleButton +#define isCheckable isToggleButton #define setShortcut setAccel diff --git a/include/sample_buffer.h b/include/sample_buffer.h index da910da99b..49558cb3bc 100644 --- a/include/sample_buffer.h +++ b/include/sample_buffer.h @@ -72,6 +72,7 @@ public: sampleBuffer( const QString & _audio_file = "", bool _is_base64_data = FALSE ); sampleBuffer( const sampleFrame * _data, Uint32 _frames ); + sampleBuffer( Uint32 _frames ); ~sampleBuffer(); @@ -80,32 +81,40 @@ public: mixer::inst()->framesPerAudioBuffer(), float _freq = BASE_FREQ, bool _looped = FALSE, void * * _resampling_data = NULL ); + void FASTCALL drawWaves( QPainter & _p, QRect _dr, drawMethods _dm = LINE_CONNECT ); + inline const QString & audioFile( void ) const { return( m_audioFile ); } + inline Uint32 startFrame( void ) const { return( m_startFrame ); } + inline Uint32 endFrame( void ) const { return( m_endFrame ); } + inline Uint32 frames( void ) const { return( m_frames ); } + inline float amplification( void ) const { return( m_amplification ); } + inline bool reversed( void ) const { return( m_reversed ); } + inline const sampleFrame * data( void ) const { return( m_data ); @@ -118,6 +127,21 @@ public: QString toBase64( void ) const; + static sampleBuffer * FASTCALL resample( sampleFrame * _data, + const Uint32 _frames, + const Uint32 _src_sr, + const Uint32 _dst_sr ); + + static inline sampleBuffer * FASTCALL resample( + sampleBuffer * _buf, + const Uint32 _src_sr, + const Uint32 _dst_sr ) + { + return( resample( _buf->m_data, _buf->m_frames, _src_sr, + _dst_sr ) ); + } + + public slots: void setAudioFile( const QString & _audio_file ); void loadFromBase64( const QString & _data ); @@ -132,15 +156,18 @@ private: #ifdef SDL_SDL_SOUND_H Uint32 FASTCALL decodeSampleSDL( const char * _f, Sint16 * & _buf, - Uint8 & _channels ); + Uint8 & _channels, + Uint32 & _sample_rate ); #endif #ifdef HAVE_SNDFILE_H Uint32 FASTCALL decodeSampleSF( const char * _f, Sint16 * & _buf, - Uint8 & _channels ); + Uint8 & _channels, + Uint32 & _sample_rate ); #endif #ifdef HAVE_VORBIS_VORBISFILE_H - Uint32 FASTCALL decodeSampleOGG( const char * _f, Sint16 * & _buf, - Uint8 & _channels ); + Uint32 FASTCALL decodeSampleOGGVorbis( const char * _f, Sint16 * & _buf, + Uint8 & _channels, + Uint32 & _sample_rate ); #endif QString m_audioFile; diff --git a/include/tool_button.h b/include/tool_button.h index c4639bbe85..6a80153e83 100644 --- a/include/tool_button.h +++ b/include/tool_button.h @@ -43,6 +43,7 @@ class toolButton : public QToolButton { + Q_OBJECT public: toolButton( const QPixmap & _pixmap, const QString & _tooltip, QObject * _receiver, const char * _slot, @@ -57,7 +58,7 @@ public: leaveEvent( NULL ); } - ~toolButton(); + virtual ~toolButton(); inline void setStandardColor( const QColor & _color ) { @@ -82,6 +83,10 @@ protected: virtual void leaveEvent( QEvent * _ev ); +private slots: + void toggledBool( bool _on ); + + private: static const QColor s_stdColor; static const QColor s_hlColor; diff --git a/include/track.h b/include/track.h index 201a2d052c..1976dd2ae3 100644 --- a/include/track.h +++ b/include/track.h @@ -58,6 +58,7 @@ class QMenu; +class QPushButton; class pixmapButton; class textFloat; @@ -66,7 +67,7 @@ class trackContainer; class trackContentWidget; class trackWidget; -typedef QWidget trackOperationsWidget; +typedef QWidget trackSettingsWidget; @@ -111,12 +112,13 @@ protected: virtual void constructContextMenu( QMenu * ) { } + virtual void contextMenuEvent( QContextMenuEvent * _cme ); virtual void dragEnterEvent( QDragEnterEvent * _dee ); virtual void dropEvent( QDropEvent * _de ); virtual void leaveEvent( QEvent * _e ); - virtual void mouseMoveEvent( QMouseEvent * _me ); virtual void mousePressEvent( QMouseEvent * _me ); + virtual void mouseMoveEvent( QMouseEvent * _me ); virtual void mouseReleaseEvent( QMouseEvent * _me ); void setAutoResizeEnabled( bool _e = FALSE ); @@ -203,20 +205,39 @@ private: -class trackSettingsWidget : public QWidget +class trackOperationsWidget : public QWidget { + Q_OBJECT public: - trackSettingsWidget( trackWidget * _parent ); - ~trackSettingsWidget(); + trackOperationsWidget( trackWidget * _parent ); + ~trackOperationsWidget(); + + bool muted( void ) const; + + +public slots: + void setMuted( bool _muted ); protected: virtual void mousePressEvent( QMouseEvent * _me ); + virtual void paintEvent( QPaintEvent * _pe ); + + +private slots: + void cloneTrack( void ); + void removeTrack( void ); + void muteBtnRightClicked( void ); private: + static QPixmap * s_grip; + trackWidget * m_trackWidget; + QPushButton * m_trackOps; + pixmapButton * m_muteBtn; + } ; @@ -242,6 +263,12 @@ public: return( m_track ); } + inline const trackOperationsWidget & getTrackOperationsWidget( void ) + const + { + return( m_trackOperationsWidget ); + } + inline const trackSettingsWidget & getTrackSettingsWidget( void ) const { return( m_trackSettingsWidget ); @@ -252,6 +279,11 @@ public: return( m_trackContentWidget ); } + inline trackOperationsWidget & getTrackOperationsWidget( void ) + { + return( m_trackOperationsWidget ); + } + inline trackSettingsWidget & getTrackSettingsWidget( void ) { return( m_trackSettingsWidget ); @@ -262,22 +294,22 @@ public: return( m_trackContentWidget ); } - bool muted( void ) const; - + bool isMovingTrack( void ) const + { + return( m_movingTrack ); + } + public slots: void changePosition( const midiTime & _new_pos = -1 ); - void cloneTrack( void ); - void removeTrack( void ); - void moveTrackUp( void ); - void moveTrackDown( void ); - void setMuted( bool _muted ); - void muteBtnRightClicked( void ); protected: virtual void dragEnterEvent( QDragEnterEvent * _dee ); virtual void dropEvent( QDropEvent * _de ); + virtual void mousePressEvent( QMouseEvent * _me ); + virtual void mouseMoveEvent( QMouseEvent * _me ); + virtual void mouseReleaseEvent( QMouseEvent * _me ); virtual void paintEvent( QPaintEvent * _pe ); virtual void resizeEvent( QResizeEvent * _re ); @@ -291,7 +323,8 @@ private: trackSettingsWidget m_trackSettingsWidget; trackContentWidget m_trackContentWidget; - pixmapButton * m_muteBtn; + bool m_movingTrack; + Sint16 m_initialMouseX; } ; @@ -324,9 +357,15 @@ public: inline bool muted( void ) const { - return( m_trackWidget->muted() ); + return( m_trackWidget->getTrackOperationsWidget().muted() ); } + inline void setMuted( bool _muted ) + { + m_trackWidget->getTrackOperationsWidget().setMuted( _muted ); + } + + // pure virtual functions virtual trackTypes type( void ) const = 0; diff --git a/include/track_container.h b/include/track_container.h index 2abee84add..0486308b02 100644 --- a/include/track_container.h +++ b/include/track_container.h @@ -55,28 +55,35 @@ class trackContainer : public QMainWindow, public settings { Q_OBJECT public: - trackContainer(); + trackContainer( void ); ~trackContainer(); + inline QWidget * containerWidget( void ) { return( m_scrollArea ); } + virtual void FASTCALL saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + inline float pixelsPerTact( void ) const { return( m_ppt ); } + inline const midiTime & currentPosition( void ) const { return( m_currentPosition ); } + virtual bool fixedTCOs( void ) const { return( FALSE ); } + unsigned int FASTCALL countTracks( track::trackTypes _tt = track::TOTAL_TRACK_TYPES ) const; @@ -92,6 +99,8 @@ public: void FASTCALL moveTrackDown( track * _track ); void FASTCALL realignTracks( bool _complete_update = FALSE ); + const trackWidget * trackWidgetAt( const int _y ) const; + protected: virtual void dragEnterEvent( QDragEnterEvent * _dee ); diff --git a/include/visualization_widget.h b/include/visualization_widget.h index 08b580926f..6bc60b8d62 100644 --- a/include/visualization_widget.h +++ b/include/visualization_widget.h @@ -6,7 +6,7 @@ * 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 + * 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. * diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index a8f71cc3f7..bbb984456d 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -89,8 +89,7 @@ QPixmap * audioFileProcessor::s_artwork = NULL; audioFileProcessor::audioFileProcessor( channelTrack * _channel_track ) : - instrument( _channel_track, - audiofileprocessor_plugin_descriptor.public_name ), + instrument( _channel_track, &audiofileprocessor_plugin_descriptor ), specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ), m_sampleBuffer( "" ), m_drawMethod( sampleBuffer::LINE_CONNECT ) @@ -298,6 +297,10 @@ void audioFileProcessor::saveSettings( QDomDocument & _doc, { QDomElement afp_de = _doc.createElement( nodeName() ); afp_de.setAttribute( "src", m_sampleBuffer.audioFile() ); + if( m_sampleBuffer.audioFile() == "" ) + { + afp_de.setAttribute( "sampledata", m_sampleBuffer.toBase64() ); + } afp_de.setAttribute( "sframe", QString::number( m_sampleBuffer.startFrame() / (float)m_sampleBuffer.frames() ) ); @@ -317,7 +320,14 @@ void audioFileProcessor::saveSettings( QDomDocument & _doc, void audioFileProcessor::loadSettings( const QDomElement & _this ) { - setAudioFile( _this.attribute( "src" ) ); + if( _this.attribute( "src" ) != "" ) + { + setAudioFile( _this.attribute( "src" ) ); + } + else if( _this.attribute( "sampledata" ) != "" ) + { + m_sampleBuffer.loadFromBase64( _this.attribute( "srcdata" ) ); + } setStartAndEndKnob( _this.attribute( "sframe" ).toFloat(), _this.attribute( "eframe" ).toFloat() ); m_reverseButton->setChecked( _this.attribute( "reversed" ).toInt() ); @@ -339,10 +349,14 @@ QString audioFileProcessor::nodeName( void ) const void audioFileProcessor::setParameter( const QString & _param, const QString & _value ) { - if( _param == "audiofile" ) + if( _param == "samplefile" ) { setAudioFile( _value ); } + else if( _param == "sampledata" ) + { + m_sampleBuffer.loadFromBase64( _value ); + } } diff --git a/plugins/audio_file_processor/audio_file_processor.h b/plugins/audio_file_processor/audio_file_processor.h index 8d9a4f87f9..48b61a2359 100644 --- a/plugins/audio_file_processor/audio_file_processor.h +++ b/plugins/audio_file_processor/audio_file_processor.h @@ -2,7 +2,7 @@ * audio_file_processor.h - declaration of class audioFileProcessor * (instrument-plugin for using audio-files) * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * diff --git a/plugins/plucked_string_synth/plucked_string_synth.cpp b/plugins/plucked_string_synth/plucked_string_synth.cpp index 0d769f620a..eb8b56af6b 100644 --- a/plugins/plucked_string_synth/plucked_string_synth.cpp +++ b/plugins/plucked_string_synth/plucked_string_synth.cpp @@ -1,7 +1,7 @@ /* * plucked_string_synth.cpp - instrument which uses the Karplus-Strong-algorithm * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -70,8 +70,7 @@ plugin::descriptor pluckedstringsynth_plugin_descriptor = // add distortion pluckedStringSynth::pluckedStringSynth( channelTrack * _channel_track ) : - instrument( _channel_track, - pluckedstringsynth_plugin_descriptor.public_name ) + instrument( _channel_track, &pluckedstringsynth_plugin_descriptor ) { m_pickKnob = new knob( knobDark_28, this, tr( "Pick position" ) ); m_pickKnob->setRange( 0.0f, 0.5f, 0.005f ); diff --git a/plugins/plucked_string_synth/plucked_string_synth.h b/plugins/plucked_string_synth/plucked_string_synth.h index 62c3be0005..f16dd6463a 100644 --- a/plugins/plucked_string_synth/plucked_string_synth.h +++ b/plugins/plucked_string_synth/plucked_string_synth.h @@ -2,7 +2,7 @@ * plucked_string_sytn.h - declaration of class pluckedStringSynth which * is a synth for plucked string-sounds * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * diff --git a/plugins/triple_oscillator/triple_oscillator.cpp b/plugins/triple_oscillator/triple_oscillator.cpp index 46dfc7551c..e944ee0871 100644 --- a/plugins/triple_oscillator/triple_oscillator.cpp +++ b/plugins/triple_oscillator/triple_oscillator.cpp @@ -1,7 +1,7 @@ /* * triple_oscillator.cpp - powerful instrument with three oscillators * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -77,14 +77,14 @@ plugin::descriptor tripleoscillator_plugin_descriptor = tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : - instrument( _channel_track, - tripleoscillator_plugin_descriptor.public_name ), + instrument( _channel_track, &tripleoscillator_plugin_descriptor ), m_modulationAlgo1( oscillator::MIX ), m_modulationAlgo2( oscillator::MIX ) { #ifdef QT4 QPalette pal; - pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) ); + pal.setBrush( backgroundRole(), + PLUGIN_NAME::getIconPixmap( "artwork" ) ); setPalette( pal ); #else setErasePixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) ); @@ -92,7 +92,8 @@ tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : m_fm1OscBtn = new pixmapButton( this ); m_fm1OscBtn->move( 80, 50 ); - m_fm1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "fm_active" ) ); + m_fm1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "fm_active" ) ); m_fm1OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "fm_inactive" ) ); m_fm1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). @@ -105,7 +106,8 @@ tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : m_am1OscBtn = new pixmapButton( this ); m_am1OscBtn->move( 120, 50 ); - m_am1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "am_active" ) ); + m_am1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "am_active" ) ); m_am1OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "am_inactive" ) ); m_am1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). @@ -118,11 +120,12 @@ tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : m_mix1OscBtn = new pixmapButton( this ); m_mix1OscBtn->move( 160, 50 ); - m_mix1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "mix_active" ) ); + m_mix1OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "mix_active" ) ); m_mix1OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "mix_inactive" ) ); - m_mix1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); + m_mix1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( + "btn_mask" ).createHeuristicMask() ) ); connect( m_mix1OscBtn, SIGNAL( toggled( bool ) ), this, SLOT( mix1BtnToggled( bool ) ) ); toolTip::add( m_mix1OscBtn, tr( "mix output of oscillator 1 & 2" ) ); @@ -133,8 +136,8 @@ tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : "sync_active" ) ); m_sync1OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "sync_inactive" ) ); - m_sync1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); + m_sync1OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( + "btn_mask" ).createHeuristicMask() ) ); connect( m_sync1OscBtn, SIGNAL( toggled( bool ) ), this, SLOT( sync1BtnToggled( bool ) ) ); toolTip::add( m_sync1OscBtn, tr( "synchronize oscillator 1 with " @@ -169,7 +172,8 @@ tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : m_fm2OscBtn = new pixmapButton( this ); m_fm2OscBtn->move( 80, 70 ); - m_fm2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "fm_active" ) ); + m_fm2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "fm_active" ) ); m_fm2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "fm_inactive" ) ); m_fm2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). @@ -182,8 +186,10 @@ tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : m_am2OscBtn = new pixmapButton( this ); m_am2OscBtn->move( 120, 70 ); - m_am2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "am_active" ) ); - m_am2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap("am_inactive" ) ); + m_am2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "am_active" ) ); + m_am2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "am_inactive" ) ); m_am2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). createHeuristicMask() ) ); connect( m_am2OscBtn, SIGNAL( toggled( bool ) ), this, @@ -194,11 +200,12 @@ tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : m_mix2OscBtn = new pixmapButton( this ); m_mix2OscBtn->move( 160, 70 ); - m_mix2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "mix_active" ) ); + m_mix2OscBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "mix_active" ) ); m_mix2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "mix_inactive" ) ); - m_mix2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); + m_mix2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( + "btn_mask" ).createHeuristicMask() ) ); connect( m_mix2OscBtn, SIGNAL( toggled( bool ) ), this, SLOT( mix2BtnToggled( bool ) ) ); toolTip::add( m_mix2OscBtn, tr("mix output of oscillator 2 & 3" ) ); @@ -209,8 +216,8 @@ tripleOscillator::tripleOscillator( channelTrack * _channel_track ) : "sync_active" ) ); m_sync2OscBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "sync_inactive" ) ); - m_sync2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); + m_sync2OscBtn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( + "btn_mask" ).createHeuristicMask() ) ); connect( m_sync2OscBtn, SIGNAL( toggled( bool ) ), this, SLOT( sync2BtnToggled( bool ) ) ); toolTip::add( m_sync2OscBtn, tr( "synchronize oscillator 2 with " diff --git a/plugins/triple_oscillator/triple_oscillator.h b/plugins/triple_oscillator/triple_oscillator.h index 35d9c35da8..6010dcbb55 100644 --- a/plugins/triple_oscillator/triple_oscillator.h +++ b/plugins/triple_oscillator/triple_oscillator.h @@ -2,7 +2,7 @@ * triple_oscillator.h - declaration of class tripleOscillator a powerful * instrument-plugin with 3 oscillators * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * diff --git a/plugins/vestige/communication.h b/plugins/vestige/communication.h index 3151892e43..2de5c0cb3a 100644 --- a/plugins/vestige/communication.h +++ b/plugins/vestige/communication.h @@ -16,6 +16,7 @@ inline T readValue( int _fd = 0 ) + template inline void writeValue( const T & _i, int _fd = 1 ) { @@ -23,44 +24,6 @@ inline void writeValue( const T & _i, int _fd = 1 ) } -enum vstRemoteCommands -{ - // client -> server - LOAD_VST_PLUGIN = 0, - CLOSE_VST_PLUGIN, - PROCESS = 10, - ENQUEUE_MIDI_EVENT = 11, - SET_SAMPLE_RATE = 20, - SET_BUFFER_SIZE, - GET_SHM_KEY_AND_SIZE, - GET_VST_VERSION = 30, - GET_NAME, - GET_VENDOR_STRING, - GET_PRODUCT_STRING, - - // server -> client - SET_SHM_KEY_AND_SIZE = 100, - SET_INPUT_COUNT, - SET_OUTPUT_COUNT, - SET_XID, - INITIALIZATION_DONE, - FAILED_LOADING_PLUGIN, - QUIT_ACK, - GET_SAMPLE_RATE = 110, - GET_BUFFER_SIZE, - GET_BPM, - SET_VST_VERSION, - SET_NAME, - SET_VENDOR_STRING, - SET_PRODUCT_STRING, - PROCESS_DONE = 120, - - DEBUG_MSG = 200, - UNDEFINED_CMD - -} ; - - static inline std::string readString( int _fd = 0 ) @@ -84,4 +47,73 @@ static inline void writeString( const char * _str, int _fd = 1 ) } + + +struct vstParameterDumpItem +{ + Sint32 index; + char shortLabel[8]; + float value; +} ; + + + + +// summarized version of VstParameterProperties-struct - useful because client +// doesn't have to know about the latter one +struct vstParamProperties +{ + char label[64]; + char shortLabel[8]; + char categoryLabel[24]; + float minValue; + float maxValue; + float step; + Sint16 category; +} ; + + +enum vstRemoteCommands +{ + // client -> server + VST_LOAD_PLUGIN = 0, + VST_CLOSE_PLUGIN, + VST_SHOW_EDITOR, + VST_PROCESS, + VST_ENQUEUE_MIDI_EVENT, + VST_SAMPLE_RATE, + VST_BUFFER_SIZE, + VST_BPM, + VST_GET_PARAMETER_COUNT = 20, + VST_GET_PARAMETER_DUMP, + VST_SET_PARAMETER_DUMP, + VST_GET_PARAMETER_PROPERTIES, + + // server -> client + VST_INITIALIZATION_DONE = 100, + VST_FAILED_LOADING_PLUGIN, + VST_QUIT_ACK, + VST_SHM_KEY_AND_SIZE, + VST_INPUT_COUNT, + VST_OUTPUT_COUNT, + VST_PLUGIN_XID, + VST_PROCESS_DONE, + VST_PLUGIN_NAME, + VST_PLUGIN_VERSION, + VST_PLUGIN_VENDOR_STRING, + VST_PLUGIN_PRODUCT_STRING, + VST_PARAMETER_COUNT, + VST_PARAMETER_DUMP, + VST_PARAMETER_PROPERTIES, + VST_GET_SAMPLE_RATE = 120, + VST_GET_BUFFER_SIZE, + + VST_DEBUG_MSG = 200, + VST_UNDEFINED_CMD + +} ; + + + + #endif diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index 99c5a01b1d..2f6708c56e 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -1,7 +1,7 @@ /* * vestige.cpp - instrument-plugin for hosting VST-plugins * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -59,6 +59,7 @@ #include "spc_bg_hndl_widget.h" #include "vestige.h" #include "text_float.h" +#include "fstclient.h" #include "embed.cpp" @@ -71,8 +72,7 @@ plugin::descriptor vestige_plugin_descriptor = STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ), "VeSTige", QT_TRANSLATE_NOOP( "pluginBrowser", - "experimental VST-hoster for using VST-plugins " - "within LMMS" ), + "VST-host for using VST(i)-plugins within LMMS" ), "Tobias Doerffel ", 0x0100, plugin::INSTRUMENT, @@ -86,15 +86,17 @@ QPixmap * vestigeInstrument::s_artwork = NULL; vestigeInstrument::vestigeInstrument( channelTrack * _channel_track ) : - instrument( _channel_track, vestige_plugin_descriptor.public_name ), + instrument( _channel_track, &vestige_plugin_descriptor ), specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ), - m_plugin( NULL ) + m_plugin( NULL ), + m_pluginMutex() { if( s_artwork == NULL ) { s_artwork = new QPixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) ); } + #ifdef QT4 QPalette pal; pal.setBrush( backgroundRole(), *s_artwork); @@ -103,6 +105,9 @@ vestigeInstrument::vestigeInstrument( channelTrack * _channel_track ) : setErasePixmap( *s_artwork ); #endif + connect( songEditor::inst(), SIGNAL( bpmChanged( int ) ), + this, SLOT( changeBPM( int ) ) ); + m_openPluginButton = new pixmapButton( this ); m_openPluginButton->setCheckable( FALSE ); m_openPluginButton->setCursor( Qt::PointingHandCursor ); @@ -127,7 +132,9 @@ vestigeInstrument::vestigeInstrument( channelTrack * _channel_track ) : "and you can select your file." ) ); m_toggleGUIButton = new QPushButton( tr( "Show/hide VST-GUI" ), this ); - m_toggleGUIButton->setGeometry( 20, 120, 128, 24 ); + m_toggleGUIButton->setGeometry( 20, 120, 160, 24 ); + m_toggleGUIButton->setIconSet( embed::getIconPixmap( "zoom" ) ); + m_toggleGUIButton->setFont( pointSize<8>( m_toggleGUIButton->font() ) ); connect( m_toggleGUIButton, SIGNAL( clicked() ), this, SLOT( toggleGUI() ) ); #ifdef QT4 @@ -138,6 +145,14 @@ vestigeInstrument::vestigeInstrument( channelTrack * _channel_track ) : tr( "Click here to show or hide the graphical user interface " "(GUI) of your VST-plugin." ) ); + QPushButton * note_off_all_btn = new QPushButton( tr( "Turn off all " + "notes" ), this ); + note_off_all_btn->setGeometry( 20, 150, 160, 24 ); + note_off_all_btn->setIconSet( embed::getIconPixmap( "state_stop" ) ); + note_off_all_btn->setFont( pointSize<8>( note_off_all_btn->font() ) ); + connect( note_off_all_btn, SIGNAL( clicked() ), this, + SLOT( noteOffAll() ) ); + // now we need a play-handle which cares for calling play() instrumentPlayHandle * iph = new instrumentPlayHandle( this ); mixer::inst()->addPlayHandle( iph ); @@ -159,6 +174,36 @@ vestigeInstrument::~vestigeInstrument() void vestigeInstrument::loadSettings( const QDomElement & _this ) { + setParameter( "plugin", _this.attribute( "plugin" ) ); + m_pluginMutex.lock(); + if( m_plugin != NULL ) + { + if( m_plugin->pluginWidget() != NULL ) + { + if( _this.attribute( "guivisible" ).toInt() ) + { + m_plugin->pluginWidget()->show(); + } + else + { + m_plugin->pluginWidget()->hide(); + } + } + const Sint32 num_params = _this.attribute( + "numparams" ).toInt(); + if( num_params > 0 ) + { + QMap dump; + for( Sint32 i = 0; i < num_params; ++i ) + { + const QString key = "param" + + QString::number( i ); + dump[key] = _this.attribute( key ); + } + m_plugin->setParameterDump( dump ); + } + } + m_pluginMutex.unlock(); } @@ -168,6 +213,24 @@ void vestigeInstrument::saveSettings( QDomDocument & _doc, QDomElement & _parent ) { QDomElement vst_de = _doc.createElement( nodeName() ); + vst_de.setAttribute( "plugin", m_pluginDLL ); + m_pluginMutex.lock(); + if( m_plugin != NULL ) + { + if( m_plugin->pluginWidget() != NULL ) + { + vst_de.setAttribute( "guivisible", + m_plugin->pluginWidget()->isVisible() ); + } + const QMap & dump = m_plugin->parameterDump(); + vst_de.setAttribute( "numparams", dump.size() ); + for( QMap::const_iterator it = dump.begin(); + it != dump.end(); ++it ) + { + vst_de.setAttribute( it.key(), it.data() ); + } + } + m_pluginMutex.unlock(); _parent.appendChild( vst_de ); } @@ -185,8 +248,15 @@ QString vestigeInstrument::nodeName( void ) const void vestigeInstrument::setParameter( const QString & _param, const QString & _value ) { - if( _param == "plugin" ) + if( _param == "plugin" && _value != "" ) { + m_pluginMutex.lock(); + bool set_ch_name = ( m_plugin != NULL && + getChannelTrack()->name() == m_plugin->name() ) || + getChannelTrack()->name() == + channelTrack::tr( "Default" ); + m_pluginMutex.unlock(); + closePlugin(); m_pluginDLL = _value; @@ -195,9 +265,12 @@ void vestigeInstrument::setParameter( const QString & _param, tr( "Please wait while loading VST-plugin..." ), PLUGIN_NAME::getIconPixmap( "logo", 24, 24 ), 0 ); + m_pluginMutex.lock(); m_plugin = new remoteVSTPlugin( m_pluginDLL ); if( m_plugin->failed() ) { + m_pluginMutex.unlock(); + closePlugin(); delete tf; QMessageBox::information( this, tr( "Failed loading VST-plugin" ), @@ -208,7 +281,6 @@ void vestigeInstrument::setParameter( const QString & _param, "contact an LMMS-developer!" ).arg( m_pluginDLL ), QMessageBox::Ok ); - closePlugin(); return; } /* if( m_plugin->vstVersion() < 2000 ) @@ -224,6 +296,17 @@ void vestigeInstrument::setParameter( const QString & _param, return; }*/ m_plugin->showEditor(); + m_plugin->setBPM( songEditor::inst()->getBPM() ); + if( set_ch_name == TRUE ) + { + getChannelTrack()->setName( m_plugin->name() ); + } + if( m_plugin->pluginWidget() != NULL ) + { + m_plugin->pluginWidget()->setWindowIcon( + *( getChannelTrack()->windowIcon() ) ); + } + m_pluginMutex.unlock(); update(); delete tf; } @@ -234,6 +317,7 @@ void vestigeInstrument::setParameter( const QString & _param, void vestigeInstrument::play( void ) { + QMutexLocker ml( &m_pluginMutex ); if( m_plugin == NULL ) { return; @@ -256,11 +340,14 @@ void vestigeInstrument::play( void ) void vestigeInstrument::playNote( notePlayHandle * _n ) { + m_pluginMutex.lock(); if( _n->totalFramesPlayed() == 0 && m_plugin != NULL ) { - m_plugin->enqueueMidiEvent( midiEvent( NOTE_ON, 0, _n->key(), + m_plugin->enqueueMidiEvent( midiEvent( NOTE_ON, 0, + getChannelTrack()->masterKey( _n ), _n->getVolume() ), _n->framesAhead() ); } + m_pluginMutex.unlock(); } @@ -268,11 +355,14 @@ void vestigeInstrument::playNote( notePlayHandle * _n ) void vestigeInstrument::deleteNotePluginData( notePlayHandle * _n ) { + m_pluginMutex.lock(); if( m_plugin != NULL ) { - m_plugin->enqueueMidiEvent( midiEvent( NOTE_OFF, 0, _n->key(), + m_plugin->enqueueMidiEvent( midiEvent( NOTE_OFF, 0, + getChannelTrack()->masterKey( _n ), 0 ), 0 ); } + m_pluginMutex.unlock(); } @@ -337,6 +427,7 @@ void vestigeInstrument::openPlugin( void ) void vestigeInstrument::toggleGUI( void ) { + QMutexLocker ml( &m_pluginMutex ); if( m_plugin == NULL ) { return; @@ -359,6 +450,36 @@ void vestigeInstrument::toggleGUI( void ) +void vestigeInstrument::noteOffAll( void ) +{ + m_pluginMutex.lock(); + if( m_plugin != NULL ) + { + for( int key = 0; key < OCTAVES * NOTES_PER_OCTAVE; ++key ) + { + m_plugin->enqueueMidiEvent( midiEvent( NOTE_OFF, 0, + key, 0 ), 0 ); + } + } + m_pluginMutex.unlock(); +} + + + + +void vestigeInstrument::changeBPM( int _new_val ) +{ + m_pluginMutex.lock(); + if( m_plugin != NULL ) + { + m_plugin->setBPM( _new_val ); + } + m_pluginMutex.unlock(); +} + + + + void vestigeInstrument::paintEvent( QPaintEvent * ) { #ifdef QT4 @@ -372,8 +493,9 @@ void vestigeInstrument::paintEvent( QPaintEvent * ) p.drawPixmap( 0, 0, *s_artwork ); - QString plugin_name = ( m_plugin ) ? - QString( m_plugin->name() ) + QString plugin_name = ( m_plugin != NULL ) ? + m_plugin->name()/* + QString::number( + m_plugin->version() )*/ : tr( "No VST-plugin loaded" ); QFont f = p.font(); @@ -383,6 +505,7 @@ void vestigeInstrument::paintEvent( QPaintEvent * ) p.drawText( 20, 80, plugin_name ); +// m_pluginMutex.lock(); if( m_plugin != NULL ) { p.setPen( QColor( 64, 128, 64 ) ); @@ -391,6 +514,8 @@ void vestigeInstrument::paintEvent( QPaintEvent * ) p.drawText( 20, 94, tr( "by" ) + " " + m_plugin->vendorString() ); } +// m_pluginMutex.unlock(); + #ifndef QT4 bitBlt( this, rect().topLeft(), &pm ); #endif @@ -401,8 +526,10 @@ void vestigeInstrument::paintEvent( QPaintEvent * ) void vestigeInstrument::closePlugin( void ) { + m_pluginMutex.lock(); delete m_plugin; m_plugin = NULL; + m_pluginMutex.unlock(); } diff --git a/plugins/vestige/vestige.h b/plugins/vestige/vestige.h index 0574553f02..1f358600c7 100644 --- a/plugins/vestige/vestige.h +++ b/plugins/vestige/vestige.h @@ -1,7 +1,7 @@ /* * vestige.h - instrument VeSTige for hosting VST-plugins * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -31,16 +31,15 @@ #ifdef QT4 -#include +#include #else -#include +#include #endif -#include "fstclient.h" #include "spc_bg_hndl_widget.h" @@ -76,6 +75,8 @@ public: protected slots: void openPlugin( void ); void toggleGUI( void ); + void noteOffAll( void ); + void changeBPM( int _new_val ); protected: @@ -89,6 +90,7 @@ private: remoteVSTPlugin * m_plugin; + QMutex m_pluginMutex; pixmapButton * m_openPluginButton; diff --git a/resources/midi_in.png b/resources/midi_in.png index ed2e891e79..c56a85b736 100644 Binary files a/resources/midi_in.png and b/resources/midi_in.png differ diff --git a/resources/midi_out.png b/resources/midi_out.png index 708f2169df..c933f5f71c 100644 Binary files a/resources/midi_out.png and b/resources/midi_out.png differ diff --git a/resources/track_op_grip.png b/resources/track_op_grip.png new file mode 100644 index 0000000000..6542a83f71 Binary files /dev/null and b/resources/track_op_grip.png differ diff --git a/resources/track_op_menu.png b/resources/track_op_menu.png new file mode 100644 index 0000000000..cc7f2d5e76 Binary files /dev/null and b/resources/track_op_menu.png differ diff --git a/src/audio/audio_alsa.cpp b/src/audio/audio_alsa.cpp index 2f93d2da80..01dd450699 100644 --- a/src/audio/audio_alsa.cpp +++ b/src/audio/audio_alsa.cpp @@ -181,7 +181,11 @@ void audioALSA::startProcessing( void ) { if( !isRunning() ) { - start(); + start( +#if QT_VERSION >= 0x030200 + QThread::HighestPriority +#endif + ); } } diff --git a/src/audio/audio_jack.cpp b/src/audio/audio_jack.cpp index b1fafb8e7a..388bf5829a 100644 --- a/src/audio/audio_jack.cpp +++ b/src/audio/audio_jack.cpp @@ -43,6 +43,9 @@ #endif +#include + + #include "debug.h" #include "templates.h" #include "gui_templates.h" diff --git a/src/audio/audio_oss.cpp b/src/audio/audio_oss.cpp index 2547458be3..18f3bf022d 100644 --- a/src/audio/audio_oss.cpp +++ b/src/audio/audio_oss.cpp @@ -284,7 +284,11 @@ void audioOSS::startProcessing( void ) { if( !isRunning() ) { - start(); + start( +#if QT_VERSION >= 0x030200 + QThread::HighestPriority +#endif + ); } } diff --git a/src/core/about_dialog.cpp b/src/core/about_dialog.cpp index 21975d77ab..a6ac795006 100644 --- a/src/core/about_dialog.cpp +++ b/src/core/about_dialog.cpp @@ -1,7 +1,7 @@ /* * about_dialog.cpp - implementation of about-dialog * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -65,13 +65,13 @@ aboutDialog::aboutDialog() : m_appNameLbl = new QLabel( tr( "Linux MultiMedia Studio %1" ).arg( VERSION ), this ); - m_appNameLbl->setGeometry( 80, 30, 240, 20 ); + m_appNameLbl->setGeometry( 80, 30, 280, 20 ); m_aboutTabs = new QTabWidget( this ); QLabel * about_lbl = new QLabel( tr( "LMMS - A powerful " "synthesizer-studio\n\n" - "Copyright (c) 2004-2005 " + "Copyright (c) 2004-2006 " "LMMS-Developers\n\n" "http://lmms.sourceforge.net" ) #ifndef QT4 diff --git a/src/core/arp_and_chords_tab_widget.cpp b/src/core/arp_and_chords_tab_widget.cpp index 216974d08b..ff0cc16e63 100644 --- a/src/core/arp_and_chords_tab_widget.cpp +++ b/src/core/arp_and_chords_tab_widget.cpp @@ -46,9 +46,9 @@ #endif -#ifdef HAVE_STDLIB_H +/*#ifdef HAVE_STDLIB_H*/ #include -#endif +/*#endif*/ #include "arp_and_chords_tab_widget.h" @@ -607,37 +607,26 @@ void arpAndChordsTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _parent ) { QDomElement act_de = _doc.createElement( nodeName() ); - act_de.setAttribute( "chorddisabled", QString::number( - !m_chordsGroupBox->isActive() ) ); + act_de.setAttribute( "chorddisabled", !m_chordsGroupBox->isActive() ); #ifdef QT4 - act_de.setAttribute( "chord", QString::number( - m_chordsComboBox->currentIndex() ) ); + act_de.setAttribute( "chord", m_chordsComboBox->currentIndex() ); #else - act_de.setAttribute( "chord", QString::number( - m_chordsComboBox->currentItem() ) ); + act_de.setAttribute( "chord", m_chordsComboBox->currentItem() ); #endif - act_de.setAttribute( "chordrange", QString::number( - m_chordRangeKnob->value() ) ); + act_de.setAttribute( "chordrange", m_chordRangeKnob->value() ); - act_de.setAttribute( "arpdisabled", QString::number( - !m_arpGroupBox->isActive() ) ); + act_de.setAttribute( "arpdisabled", !m_arpGroupBox->isActive() ); #ifdef QT4 - act_de.setAttribute( "arp", QString::number( - m_arpComboBox->currentIndex() ) ); + act_de.setAttribute( "arp", m_arpComboBox->currentIndex() ); #else - act_de.setAttribute( "arp", QString::number( - m_arpComboBox->currentItem() ) ); + act_de.setAttribute( "arp", m_arpComboBox->currentItem() ); #endif - act_de.setAttribute( "arprange", QString::number( - m_arpRangeKnob->value() ) ); - act_de.setAttribute( "arptime", QString::number( - m_arpTimeKnob->value() ) ); - act_de.setAttribute( "arpgate", QString::number( - m_arpGateKnob->value() ) ); - act_de.setAttribute( "arpdir", QString::number( - m_arpDirection ) ); - act_de.setAttribute( "arpsyncmode", QString::number( - ( int ) m_arpTimeKnob->getSyncMode() ) ); + act_de.setAttribute( "arprange", m_arpRangeKnob->value() ); + act_de.setAttribute( "arptime", m_arpTimeKnob->value() ); + act_de.setAttribute( "arpgate", m_arpGateKnob->value() ); + act_de.setAttribute( "arpdir", m_arpDirection ); + act_de.setAttribute( "arpsyncmode", + ( int ) m_arpTimeKnob->getSyncMode() ); _parent.appendChild( act_de ); diff --git a/src/core/config_mgr.cpp b/src/core/config_mgr.cpp index 0f3ca2d014..1562b016be 100644 --- a/src/core/config_mgr.cpp +++ b/src/core/config_mgr.cpp @@ -767,7 +767,7 @@ bool configManager::loadConfigFile( void ) // get the head information from the DOM QDomElement root = dom_tree.documentElement(); -/* if( root.isElement() ) + if( root.isElement() ) { QString cfg_file_ver = root.toElement().attribute( "version" ); if( ( cfg_file_ver.length() == 0 || cfg_file_ver != VERSION ) && @@ -798,7 +798,7 @@ bool configManager::loadConfigFile( void ) return( loadConfigFile() ); } } - }*/ + } QDomNode node = root.firstChild(); diff --git a/src/core/envelope_and_lfo_widget.cpp b/src/core/envelope_and_lfo_widget.cpp index 4dd7b556db..33fbc4b93d 100644 --- a/src/core/envelope_and_lfo_widget.cpp +++ b/src/core/envelope_and_lfo_widget.cpp @@ -583,31 +583,22 @@ float FASTCALL envelopeAndLFOWidget::level( Uint32 _frame, void envelopeAndLFOWidget::saveSettings( QDomDocument & , QDomElement & _parent ) { - _parent.setAttribute( "pdel", QString::number( - m_predelayKnob->value() ) ); - _parent.setAttribute( "att", QString::number( m_attackKnob->value() ) ); - _parent.setAttribute( "hold", QString::number( m_holdKnob->value() ) ); - _parent.setAttribute( "dec", QString::number( m_decayKnob->value() ) ); - _parent.setAttribute( "sus", QString::number( - m_sustainKnob->value() ) ); - _parent.setAttribute( "rel", QString::number( - m_releaseKnob->value() ) ); - _parent.setAttribute( "amt", QString::number( m_amountKnob->value() ) ); - _parent.setAttribute( "lshp", QString::number( m_lfoShape ) ); - _parent.setAttribute( "lpdel", QString::number( - m_lfoPredelayKnob->value() ) ); - _parent.setAttribute( "latt", QString::number( - m_lfoAttackKnob->value() ) ); - _parent.setAttribute( "lspd", QString::number( - m_lfoSpeedKnob->value() ) ); - _parent.setAttribute( "lamt", QString::number( - m_lfoAmountKnob->value() ) ); - _parent.setAttribute( "x100", QString::number( - m_x100Cb->isChecked() ) ); - _parent.setAttribute( "ctlenvamt", QString::number( - m_controlEnvAmountCb->isChecked() ) ); - _parent.setAttribute( "lfosyncmode", QString::number( - ( int ) m_lfoSpeedKnob->getSyncMode() ) ); + _parent.setAttribute( "pdel", m_predelayKnob->value() ); + _parent.setAttribute( "att", m_attackKnob->value() ); + _parent.setAttribute( "hold", m_holdKnob->value() ); + _parent.setAttribute( "dec", m_decayKnob->value() ); + _parent.setAttribute( "sus", m_sustainKnob->value() ); + _parent.setAttribute( "rel", m_releaseKnob->value() ); + _parent.setAttribute( "amt", m_amountKnob->value() ); + _parent.setAttribute( "lshp", m_lfoShape ); + _parent.setAttribute( "lpdel", m_lfoPredelayKnob->value() ); + _parent.setAttribute( "latt", m_lfoAttackKnob->value() ); + _parent.setAttribute( "lspd", m_lfoSpeedKnob->value() ); + _parent.setAttribute( "lamt", m_lfoAmountKnob->value() ); + _parent.setAttribute( "x100", m_x100Cb->isChecked() ); + _parent.setAttribute( "ctlenvamt", m_controlEnvAmountCb->isChecked() ); + _parent.setAttribute( "lfosyncmode", + ( int ) m_lfoSpeedKnob->getSyncMode() ); _parent.setAttribute( "userwavefile", m_userWave.audioFile() ); } diff --git a/src/core/envelope_tab_widget.cpp b/src/core/envelope_tab_widget.cpp index 4e06e71a65..b7bdcf1b65 100644 --- a/src/core/envelope_tab_widget.cpp +++ b/src/core/envelope_tab_widget.cpp @@ -493,19 +493,13 @@ void envelopeTabWidget::saveSettings( QDomDocument & _doc, { QDomElement etw_de = _doc.createElement( nodeName() ); #ifdef QT4 - etw_de.setAttribute( "ftype", QString::number( - m_filterComboBox->currentIndex() ) ); + etw_de.setAttribute( "ftype", m_filterComboBox->currentIndex() ); #else - etw_de.setAttribute( "ftype", QString::number( - m_filterComboBox->currentItem() ) ); + etw_de.setAttribute( "ftype", m_filterComboBox->currentItem() ); #endif - etw_de.setAttribute( "fcut", QString::number( - m_filterCutKnob->value() ) ); - etw_de.setAttribute( "fres", QString::number( - m_filterResKnob->value() ) ); - etw_de.setAttribute( "fwet", QString::number( - /*m_filterState->isChecked()*/ - m_filterGroupBox->isActive() ) ); + etw_de.setAttribute( "fcut", m_filterCutKnob->value() ); + etw_de.setAttribute( "fres", m_filterResKnob->value() ); + etw_de.setAttribute( "fwet", m_filterGroupBox->isActive() ); _parent.appendChild( etw_de ); for( int i = 0; i < TARGET_COUNT; ++i ) diff --git a/src/core/file_browser.cpp b/src/core/file_browser.cpp index 3fc11125a1..7a90923de5 100644 --- a/src/core/file_browser.cpp +++ b/src/core/file_browser.cpp @@ -226,7 +226,7 @@ void fileBrowser::sendToActiveChannel( void ) "audiofileprocessor" ); if( afp != NULL ) { - afp->setParameter( "audiofile", + afp->setParameter( "samplefile", m_contextMenuItem->fullName() ); } } @@ -265,7 +265,7 @@ void fileBrowser::openInNewChannel( trackContainer * _tc ) instrument * afp = ct->loadInstrument( "audiofileprocessor" ); if( afp != NULL ) { - afp->setParameter( "audiofile", + afp->setParameter( "samplefile", m_contextMenuItem->fullName() ); } ct->toggledChannelButton( TRUE ); @@ -354,7 +354,8 @@ void listView::contentsMouseDoubleClickEvent( QMouseEvent * _me ) "audiofileprocessor" ); if( afp != NULL ) { - afp->setParameter( "audiofile", f->fullName() ); + afp->setParameter( "samplefile", + f->fullName() ); } ct->toggledChannelButton( TRUE ); } diff --git a/src/core/instrument.cpp b/src/core/instrument.cpp index 6306662dcf..07c8887c5a 100644 --- a/src/core/instrument.cpp +++ b/src/core/instrument.cpp @@ -28,13 +28,18 @@ #include "dummy_instrument.h" -instrument::instrument( channelTrack * _channel_track, const QString & _name ) : +instrument::instrument( channelTrack * _channel_track, + const descriptor * _descriptor ) : QWidget( _channel_track->tabWidgetParent() ), - plugin( _name, INSTRUMENT ), + plugin( _descriptor ), m_channelTrack( _channel_track ), m_valid( TRUE ) { setFixedSize( 250, 250 ); + QPixmap logo; + logo.loadFromData( getDescriptor()->logo.data, + getDescriptor()->logo.size ); + m_channelTrack->setWindowIcon( logo ); } diff --git a/src/core/midi_tab_widget.cpp b/src/core/midi_tab_widget.cpp index 9dd8054379..341060a4e7 100644 --- a/src/core/midi_tab_widget.cpp +++ b/src/core/midi_tab_widget.cpp @@ -2,7 +2,7 @@ * midi_tab_widget.cpp - tab-widget in channel-track-window for setting up * MIDI-related stuff * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -80,15 +80,17 @@ midiTabWidget::midiTabWidget( channelTrack * _channel_track, m_inputChannelSpinBox->move( 28, 52 ); connect( m_inputChannelSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( inputChannelChanged( int ) ) ); + inputChannelChanged( m_inputChannelSpinBox->value() ); - m_outputChannelSpinBox = new lcdSpinBox( 0, MIDI_CHANNEL_COUNT, 3, + m_outputChannelSpinBox = new lcdSpinBox( 1, MIDI_CHANNEL_COUNT, 3, m_setupTabWidget ); - m_outputChannelSpinBox->addTextForValue( 0, "---" ); m_outputChannelSpinBox->setValue( m_midiPort->outputChannel() + 1 ); + //m_outputChannelSpinBox->addTextForValue( 0, "---" ); m_outputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); m_outputChannelSpinBox->move( 28, 112 ); connect( m_outputChannelSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( outputChannelChanged( int ) ) ); + outputChannelChanged( m_outputChannelSpinBox->value() ); m_receiveCheckBox = new ledCheckBox( tr( "RECEIVE MIDI-EVENTS" ), @@ -109,17 +111,20 @@ midiTabWidget::midiTabWidget( channelTrack * _channel_track, m_outputChannelSpinBox, SLOT( setEnabled( bool ) ) ); - midiPort::modes m = m_midiPort->mode(); + const midiPort::modes m = m_midiPort->mode(); m_receiveCheckBox->setChecked( m == midiPort::INPUT || m == midiPort::DUPLEX ); m_sendCheckBox->setChecked( m == midiPort::OUTPUT || m == midiPort::DUPLEX ); + // when using with non-raw-clients we can provide buttons showing + // our port-menus when being clicked midiClient * mc = mixer::inst()->getMIDIClient(); - // non-raw-clients have ports we can subscribe to! if( mc->isRaw() == FALSE ) { m_readablePorts = new QMenu( m_setupTabWidget ); + m_readablePorts->setFont( pointSize<9>( + m_readablePorts->font() ) ); #ifdef QT4 connect( m_readablePorts, SIGNAL( triggered( QAction * ) ), this, SLOT( activatedReadablePort( QAction * ) ) ); @@ -130,6 +135,8 @@ midiTabWidget::midiTabWidget( channelTrack * _channel_track, #endif m_writeablePorts = new QMenu( m_setupTabWidget ); + m_writeablePorts->setFont( pointSize<9>( + m_writeablePorts->font() ) ); #ifdef QT4 connect( m_writeablePorts, SIGNAL( triggered( QAction * ) ), this, SLOT( activatedWriteablePort( QAction * ) ) ); @@ -187,14 +194,10 @@ midiTabWidget::~midiTabWidget() void midiTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _parent ) { QDomElement mw_de = _doc.createElement( nodeName() ); - mw_de.setAttribute( "inputchannel", QString::number( - m_inputChannelSpinBox->value() ) ); - mw_de.setAttribute( "outputchannel", QString::number( - m_outputChannelSpinBox->value() ) ); - mw_de.setAttribute( "receive", QString::number( - m_receiveCheckBox->isChecked() ) ); - mw_de.setAttribute( "send", QString::number( - m_sendCheckBox->isChecked() ) ); + mw_de.setAttribute( "inputchannel", m_inputChannelSpinBox->value() ); + mw_de.setAttribute( "outputchannel", m_outputChannelSpinBox->value() ); + mw_de.setAttribute( "receive", m_receiveCheckBox->isChecked() ); + mw_de.setAttribute( "send", m_sendCheckBox->isChecked() ); if( m_readablePorts != NULL && m_receiveCheckBox->isChecked() == TRUE ) { @@ -600,6 +603,10 @@ void midiTabWidget::activatedWriteablePort( int _id ) void midiTabWidget::activatedReadablePort( QAction * ) { } void midiTabWidget::activatedWriteablePort( QAction * ) { } + +#undef setIcon +#undef setText + #endif diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index bf0bfda193..3020edf5c4 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -23,12 +23,6 @@ */ -#include - -#ifdef HAVE_SYS_TIME_H -#include -#endif - #include "mixer.h" #include "play_handle.h" #include "song_editor.h" @@ -38,6 +32,9 @@ #include "debug.h" #include "config_mgr.h" #include "audio_port.h" +#include "sample_play_handle.h" +#include "piano_roll.h" +#include "micro_timer.h" #include "audio_device.h" #include "midi_client.h" @@ -60,38 +57,6 @@ Uint32 SAMPLE_RATES[QUALITY_LEVELS] = { 44100, 88200 } ; -class microTimer -{ -public: - microTimer( void ) - { - reset(); - } - - ~microTimer() - { - } - - void reset( void ) - { - gettimeofday( &begin, NULL ); - } - - Uint32 elapsed( void ) const - { - struct timeval now; - gettimeofday( &now, NULL ); - return( ( now.tv_sec - begin.tv_sec ) * 1000 * 1000 + - ( now.tv_usec - begin.tv_usec ) ); - } - -private: - struct timeval begin; - -} ; - - - mixer * mixer::s_instanceOfMe = NULL; @@ -167,6 +132,18 @@ const surroundSampleFrame * mixer::renderNextBuffer( void ) { microTimer timer; + static songEditor::playPos last_metro_pos = -1; + + songEditor::playPos p = songEditor::inst()->getPlayPos( + songEditor::PLAY_PATTERN ); + if( songEditor::inst()->playMode() == songEditor::PLAY_PATTERN && + pianoRoll::inst()->isRecording() == TRUE && + p != last_metro_pos && p.getTact64th() % 16 == 0 ) + { + addPlayHandle( new samplePlayHandle( "misc/metronome01.ogg" ) ); + last_metro_pos = p; + } + // now we have to make sure no other thread does anything bad // while we're acting... m_mixMutex.lock(); @@ -205,10 +182,9 @@ const surroundSampleFrame * mixer::renderNextBuffer( void ) while( idx < m_playHandles.size() ) { register playHandle * n = m_playHandles[idx]; + // delete play-handle if it played completely if( n->done() ) { - // delete all play-handles which have - // played completely now delete n; m_playHandles.erase( m_playHandles.begin() + idx ); @@ -255,13 +231,21 @@ const surroundSampleFrame * mixer::renderNextBuffer( void ) // removes all play-handles. this is neccessary, when the song is stopped -> // all remaining notes etc. would be played until their end -void mixer::clear( void ) +void mixer::clear( bool _everything ) { // TODO: m_midiClient->noteOffAll(); for( playHandleVector::iterator it = m_playHandles.begin(); it != m_playHandles.end(); ++it ) { - m_playHandlesToRemove.push_back( *it ); + // we must not delete instrument-play-handles as they exist + // during the whole lifetime of an instrument - exception if + // parameter _everything is true (which is the case when + // clearing song for example) + if( _everything == TRUE || + ( *it )->type() != playHandle::INSTRUMENT_PLAY_HANDLE ) + { + m_playHandlesToRemove.push_back( *it ); + } } } @@ -290,9 +274,10 @@ void FASTCALL mixer::bufferToPort( sampleFrame * _buf, Uint32 _frames, volumeVector & _volume_vector, audioPort * _port ) { - Uint32 start_frame = _frames_ahead % m_framesPerAudioBuffer; + const Uint32 start_frame = _frames_ahead % m_framesPerAudioBuffer; Uint32 end_frame = start_frame + _frames; - Uint32 loop1_frame = tMin( end_frame, m_framesPerAudioBuffer ); + const Uint32 loop1_frame = tMin( end_frame, m_framesPerAudioBuffer ); + for( Uint32 frame = start_frame; frame < loop1_frame; ++frame ) { for( Uint8 chnl = 0; chnl < SURROUND_CHANNELS; ++chnl ) @@ -303,6 +288,7 @@ void FASTCALL mixer::bufferToPort( sampleFrame * _buf, Uint32 _frames, _volume_vector.vol[chnl]; } } + if( end_frame > m_framesPerAudioBuffer ) { Uint32 frames_done = m_framesPerAudioBuffer - start_frame; @@ -318,10 +304,12 @@ void FASTCALL mixer::bufferToPort( sampleFrame * _buf, Uint32 _frames, _volume_vector.vol[chnl]; } } + // we used both buffers so set flags _port->m_bufferUsage = audioPort::BOTH; } else if( _port->m_bufferUsage == audioPort::NONE ) { + // only first buffer touched _port->m_bufferUsage = audioPort::FIRST; } @@ -344,6 +332,7 @@ void mixer::setHighQuality( bool _hq_on ) { m_qualityLevel = DEFAULT_QUALITY_LEVEL; } + // and re-open device m_audioDev = tryAudioDevices(); m_audioDev->startProcessing(); @@ -423,20 +412,6 @@ audioDevice * mixer::tryAudioDevices( void ) audioDevice * dev = NULL; QString dev_name = configManager::inst()->value( "mixer", "audiodev" ); -#ifdef OSS_SUPPORT - if( dev_name == audioOSS::name() || dev_name == "" ) - { - dev = new audioOSS( SAMPLE_RATES[DEFAULT_QUALITY_LEVEL], - success_ful ); - if( success_ful ) - { - m_audioDevName = audioOSS::name(); - return( dev ); - } - delete dev; - } -#endif - #ifdef ALSA_SUPPORT if( dev_name == audioALSA::name() || dev_name == "" ) { @@ -452,6 +427,21 @@ audioDevice * mixer::tryAudioDevices( void ) #endif +#ifdef OSS_SUPPORT + if( dev_name == audioOSS::name() || dev_name == "" ) + { + dev = new audioOSS( SAMPLE_RATES[DEFAULT_QUALITY_LEVEL], + success_ful ); + if( success_ful ) + { + m_audioDevName = audioOSS::name(); + return( dev ); + } + delete dev; + } +#endif + + #ifdef JACK_SUPPORT if( dev_name == audioJACK::name() || dev_name == "" ) { diff --git a/src/core/note.cpp b/src/core/note.cpp index bae3a8319d..6abad57140 100644 --- a/src/core/note.cpp +++ b/src/core/note.cpp @@ -166,12 +166,12 @@ void note::setPanning( panning _panning ) void note::saveSettings( QDomDocument & _doc, QDomElement & _parent ) { QDomElement note_de = _doc.createElement( "note" ); - note_de.setAttribute( "tone", QString::number( m_tone ) ); - note_de.setAttribute( "oct", QString::number( m_octave ) ); - note_de.setAttribute( "vol", QString::number( m_volume ) ); - note_de.setAttribute( "pan", QString::number( m_panning ) ); - note_de.setAttribute( "len", QString::number( m_length ) ); - note_de.setAttribute( "pos", QString::number( m_pos ) ); + note_de.setAttribute( "tone", m_tone ); + note_de.setAttribute( "oct", m_octave ); + note_de.setAttribute( "vol", m_volume ); + note_de.setAttribute( "pan", m_panning ); + note_de.setAttribute( "len", m_length ); + note_de.setAttribute( "pos", m_pos ); _parent.appendChild( note_de ); } diff --git a/src/core/note_play_handle.cpp b/src/core/note_play_handle.cpp index f41fc7bd69..7390c66579 100644 --- a/src/core/note_play_handle.cpp +++ b/src/core/note_play_handle.cpp @@ -2,7 +2,7 @@ * note_play_handle.cpp - implementation of class notePlayHandle, part of * play-engine * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -34,10 +34,14 @@ #include "song_editor.h" -notePlayHandle::notePlayHandle( channelTrack * _chnl_trk, Uint32 _frames_ahead, - Uint32 _frames, note * n, bool _arp_note ) : - playHandle(), - note( *n ), + +notePlayHandle::notePlayHandle( channelTrack * _chnl_trk, + const Uint32 _frames_ahead, + const Uint32 _frames, + note * _n, + const bool _arp_note ) : + playHandle( NOTE_PLAY_HANDLE ), + note( *_n ), m_pluginData( NULL ), m_filter( NULL ), m_channelTrack( _chnl_trk ), @@ -201,6 +205,13 @@ void notePlayHandle::checkValidity( void ) if( m_channelTrack != NULL && m_channelTrack->type() == track::NULL_TRACK ) { + // track-type being track::NULL_TRACK indicates a track whose + // removal is in progress, so we have to invalidate ourself + if( m_released == FALSE ) + { + noteOff( 0 ); + } + m_channelTrack->deleteNotePluginData( this ); m_channelTrack = NULL; } // sub-notes might not be registered at mixer (for example arpeggio- diff --git a/src/core/piano_roll.cpp b/src/core/piano_roll.cpp index 6185130c76..a78b4bbbbb 100644 --- a/src/core/piano_roll.cpp +++ b/src/core/piano_roll.cpp @@ -71,7 +71,7 @@ #include "tooltip.h" #include "midi.h" #include "tool_button.h" - +#include "text_float.h" extern tones whiteKeys[]; // defined in piano_widget.cpp @@ -130,6 +130,8 @@ const int DEFAULT_PR_PPT = KEY_LINE_HEIGHT * DEFAULT_STEPS_PER_TACT; pianoRoll::pianoRoll( void ) : QWidget( lmmsMainWin::inst()->workspace() ), + m_paintPixmap(), + m_cursorInside( FALSE ), m_pattern( NULL ), m_currentPosition(), m_recording( FALSE ), @@ -522,7 +524,7 @@ void pianoRoll::setCurrentPattern( pattern * _new_pattern ) inline void pianoRoll::drawNoteRect( QPainter & _p, Uint16 _x, Uint16 _y, - Sint16 _width, bool _is_selected ) + Sint16 _width, const bool _is_selected ) { ++_x; ++_y; @@ -564,38 +566,15 @@ inline void pianoRoll::drawNoteRect( QPainter & _p, Uint16 _x, Uint16 _y, -void pianoRoll::removeSelection( void ) +void pianoRoll::update( void ) { - m_selectStartTact64th = 0; - m_selectedTact64th = 0; - m_selectStartKey = 0; - m_selectedKeys = 0; -} - - - - -void pianoRoll::closeEvent( QCloseEvent * _ce ) -{ - QApplication::restoreOverrideCursor(); - hide(); - _ce->ignore (); -} - - - - -void pianoRoll::paintEvent( QPaintEvent * ) -{ -#ifdef QT4 - QPainter p( this ); - p.fillRect( rect(), QColor( 0, 0, 0 ) ); -#else - QPixmap draw_pm( rect().size() ); - draw_pm.fill( QColor( 0, 0, 0 ) );//, rect().topLeft()); - - QPainter p( &draw_pm, this ); -#endif + if( m_paintPixmap.isNull() == TRUE || + m_paintPixmap.size() != rect().size() ) + { + m_paintPixmap = QPixmap( rect().size() ); + } + m_paintPixmap.fill( QColor( 0, 0, 0 ) ); + QPainter p( &m_paintPixmap, this ); // set font-size to 8 p.setFont( pointSize<8>( p.font() ) ); @@ -693,14 +672,6 @@ void pianoRoll::paintEvent( QPaintEvent * ) } // draw key-line p.drawLine( WHITE_KEY_WIDTH, key_line_y, width(), key_line_y ); - if( key == m_keyMouseOver ) - { - p.fillRect( WHITE_KEY_WIDTH, key_line_y - - KEY_LINE_HEIGHT, - width() - WHITE_KEY_WIDTH, - KEY_LINE_HEIGHT, - QColor( 64, 64, 64 ) ); - } ++key; } @@ -771,22 +742,11 @@ void pianoRoll::paintEvent( QPaintEvent * ) QColor( 0, 0, 0 ) ); - // draw artwork-stuff -/* p.drawPixmap( 0, 0, *s_artwork1 ); - - int artwork_x = s_artwork1->width(); - - while( artwork_x < width() ) - { - p.drawPixmap( artwork_x, 0, *s_artwork2 ); - artwork_x += s_artwork2->width(); - }*/ - - // set clipping area, because we are not allowed to paint over // keyboard... - p.setClipRect( WHITE_KEY_WIDTH, PR_TOP_MARGIN, width()-WHITE_KEY_WIDTH, - height()-PR_TOP_MARGIN-PR_BOTTOM_MARGIN ); + p.setClipRect( WHITE_KEY_WIDTH, PR_TOP_MARGIN, + width() - WHITE_KEY_WIDTH, + height() - PR_TOP_MARGIN - PR_BOTTOM_MARGIN ); // draw vertical raster int tact_16th = m_currentPosition / 4; @@ -824,7 +784,7 @@ void pianoRoll::paintEvent( QPaintEvent * ) p.setClipRect( WHITE_KEY_WIDTH, PR_TOP_MARGIN, width() - WHITE_KEY_WIDTH, height() - PR_TOP_MARGIN - - PR_BOTTOM_MARGIN ); + PR_BOTTOM_MARGIN ); // setup selection-vars int sel_pos_start = m_selectStartTact64th; @@ -950,96 +910,175 @@ void pianoRoll::paintEvent( QPaintEvent * ) #else m_leftRightScroll->setSteps( 1, l ); #endif -/* - // draw current edit-mode-icon below the cursor - switch( m_editMode ) - { - case DRAW: - p.drawPixmap( mapFromGlobal( QCursor::pos() ), - *s_toolDraw ); - break; - case ERASE: - p.drawPixmap( mapFromGlobal( QCursor::pos() ), - *s_toolErase ); - break; - case SELECT: - p.drawPixmap( mapFromGlobal( QCursor::pos() ), - *s_toolSelect ); - break; - case MOVE: - p.drawPixmap( mapFromGlobal( QCursor::pos() ), - *s_toolMove ); - break; - }*/ -#ifndef QT4 - // and blit all the drawn stuff on the screen... - bitBlt( this, rect().topLeft(), &draw_pm ); -#endif + QWidget::update(); } -// responsible for moving/resizing scrollbars after window-resizing -void pianoRoll::resizeEvent( QResizeEvent * ) +void pianoRoll::removeSelection( void ) { - - m_leftRightScroll->setGeometry( WHITE_KEY_WIDTH, height() - - SCROLLBAR_SIZE, - width()-WHITE_KEY_WIDTH, - SCROLLBAR_SIZE ); - m_topBottomScroll->setGeometry( width() - SCROLLBAR_SIZE, PR_TOP_MARGIN, - SCROLLBAR_SIZE, - height() - PR_TOP_MARGIN - - SCROLLBAR_SIZE ); - - int total_pixels = OCTAVE_HEIGHT * OCTAVES - ( height() - - PR_TOP_MARGIN - PR_BOTTOM_MARGIN - - m_notesEditHeight ); - m_totalKeysToScroll = total_pixels * NOTES_PER_OCTAVE / OCTAVE_HEIGHT; - - m_topBottomScroll->setRange( 0, m_totalKeysToScroll ); -#ifdef QT4 - m_topBottomScroll->setSingleStep( 1 ); - m_topBottomScroll->setPageStep( 20 ); -#else - m_topBottomScroll->setSteps( 1, 20 ); -#endif - - if( m_startKey > m_totalKeysToScroll ) - { - m_startKey = m_totalKeysToScroll; - } - m_topBottomScroll->setValue( m_totalKeysToScroll - m_startKey ); - - songEditor::inst()->getPlayPos( songEditor::PLAY_PATTERN - ).m_timeLine->setFixedWidth( width() ); - m_toolBar->setFixedWidth( width() ); + m_selectStartTact64th = 0; + m_selectedTact64th = 0; + m_selectStartKey = 0; + m_selectedKeys = 0; } -int pianoRoll::getKey( int _y ) +void pianoRoll::closeEvent( QCloseEvent * _ce ) { - int key_line_y = height() - PR_BOTTOM_MARGIN - m_notesEditHeight - 1; - // pressed key on piano - int key_num = ( key_line_y - _y ) / KEY_LINE_HEIGHT; - key_num += m_startKey; + QApplication::restoreOverrideCursor(); + hide(); + _ce->ignore (); +} - // some range-checking-stuff - if( key_num < 0 ) + + + +void pianoRoll::enterEvent( QEvent * _e ) +{ + m_cursorInside = TRUE; + QWidget::enterEvent( _e ); +} + + + + +void pianoRoll::keyPressEvent( QKeyEvent * _ke ) +{ + switch( _ke->key() ) { - key_num = 0; - } + case Qt::Key_Up: + m_topBottomScroll->setValue( + m_topBottomScroll->value() - 1 ); + break; - if( key_num >= NOTES_PER_OCTAVE * OCTAVES ) + case Qt::Key_Down: + m_topBottomScroll->setValue( + m_topBottomScroll->value() + 1 ); + break; + + case Qt::Key_Left: + { + if( ( m_timeLine->pos() -= 16 ) < 0 ) + { + m_timeLine->pos().setTact( 0 ); + m_timeLine->pos().setTact64th( 0 ); + } + m_timeLine->updatePosition(); + break; + } + case Qt::Key_Right: + { + m_timeLine->pos() += 16; + m_timeLine->updatePosition(); + break; + } + + case Qt::Key_C: + if( _ke->modifiers() & Qt::ControlModifier ) + { + copySelectedNotes(); + } + else + { + _ke->ignore(); + } + break; + + case Qt::Key_X: + if( _ke->modifiers() & Qt::ControlModifier ) + { + cutSelectedNotes(); + } + else + { + _ke->ignore(); + } + break; + + case Qt::Key_V: + if( _ke->modifiers() & Qt::ControlModifier ) + { + pasteNotes(); + } + else + { + _ke->ignore(); + } + break; + + case Qt::Key_A: + if( _ke->modifiers() & Qt::ControlModifier ) + { + m_selectButton->setChecked( TRUE ); + selectAll(); + update(); + } + else + { + _ke->ignore(); + } + break; + + case Qt::Key_D: + m_drawButton->setChecked( TRUE ); + break; + + case Qt::Key_E: + m_eraseButton->setChecked( TRUE ); + break; + + case Qt::Key_S: + m_selectButton->setChecked( TRUE ); + break; + + case Qt::Key_M: + m_moveButton->setChecked( TRUE ); + break; + + case Qt::Key_Delete: + deleteSelectedNotes(); + break; + + case Qt::Key_Space: + if( songEditor::inst()->playing() ) + { + stop(); + } + else + { + play(); + } + break; + + case Qt::Key_Home: + m_timeLine->pos().setTact( 0 ); + m_timeLine->pos().setTact64th( 0 ); + m_timeLine->updatePosition(); + break; + + default: + _ke->ignore(); + break; + } +} + + + + +void pianoRoll::leaveEvent( QEvent * _e ) +{ + while( QApplication::overrideCursor() != NULL ) { - key_num = NOTES_PER_OCTAVE * OCTAVES - 1; + QApplication::restoreOverrideCursor(); } + m_cursorInside = FALSE; - return( m_lastKey = key_num ); + QWidget::leaveEvent( _e ); } @@ -1324,6 +1363,7 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) // but is still on the same key) if( key_num != released_key && m_action != CHANGE_NOTE_VOLUME && + m_action != MOVE_SELECTION && edit_note == FALSE && #ifdef QT4 _me->buttons() & @@ -1344,6 +1384,7 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) Qt::LeftButton && m_action != RESIZE_NOTE && m_action != SELECT_NOTES && + m_action != MOVE_SELECTION && m_recording == FALSE && songEditor::inst()->playing() == FALSE ) { @@ -1355,7 +1396,7 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) } if( _me->x() <= WHITE_KEY_WIDTH ) { - update(); + QWidget::update(); return; } x -= WHITE_KEY_WIDTH; @@ -1427,7 +1468,13 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) songEditor::inst()->setModified(); } - else if( _me->button() == Qt::NoButton && m_editMode == DRAW ) + else if( +#ifdef QT4 + _me->buttons() & +#else + _me->state() == +#endif + Qt::NoButton && m_editMode == DRAW ) { // set move- or resize-cursor @@ -1771,130 +1818,108 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) QApplication::restoreOverrideCursor(); } - update(); + if( +#ifdef QT4 + _me->buttons() & +#else + _me->state() == +#endif + Qt::NoButton ) + { + QWidget::update(); + } + else + { + update(); + } } -void pianoRoll::keyPressEvent( QKeyEvent * _ke ) +void pianoRoll::paintEvent( QPaintEvent * ) { - switch( _ke->key() ) +#ifdef QT4 + QPainter p( this ); +#else + QPixmap draw_pm( size() ); + draw_pm.fill( QColor( 0, 0, 0 ) ); + + QPainter p( &draw_pm, this ); +#endif + p.drawPixmap( 0, 0, m_paintPixmap ); + + if( m_cursorInside == TRUE ) { - case Qt::Key_Up: - m_topBottomScroll->setValue( - m_topBottomScroll->value() - 1 ); - break; - - case Qt::Key_Down: - m_topBottomScroll->setValue( - m_topBottomScroll->value() + 1 ); - break; - - case Qt::Key_Left: + p.setClipRect( WHITE_KEY_WIDTH, PR_TOP_MARGIN, width() - + WHITE_KEY_WIDTH, height() - PR_TOP_MARGIN - + m_notesEditHeight - PR_BOTTOM_MARGIN ); + if( validPattern() == TRUE ) { - if( ( m_timeLine->pos() -= 16 ) < 0 ) - { - m_timeLine->pos().setTact( 0 ); - m_timeLine->pos().setTact64th( 0 ); - } - m_timeLine->updatePosition(); - break; - } - case Qt::Key_Right: - { - m_timeLine->pos() += 16; - m_timeLine->updatePosition(); - break; + p.fillRect( 10, height() + 3 - PR_BOTTOM_MARGIN - + m_notesEditHeight - KEY_LINE_HEIGHT * + ( m_keyMouseOver - m_startKey + 1 ), + width() - 10, KEY_LINE_HEIGHT - 7, + QColor( 64, 64, 64 ) ); } - case Qt::Key_C: - if( _ke->modifiers() & Qt::ControlModifier ) - { - copySelectedNotes(); - } - else - { - _ke->ignore(); - } - break; - - case Qt::Key_X: - if( _ke->modifiers() & Qt::ControlModifier ) - { - cutSelectedNotes(); - } - else - { - _ke->ignore(); - } - break; - - case Qt::Key_V: - if( _ke->modifiers() & Qt::ControlModifier ) - { - pasteNotes(); - } - else - { - _ke->ignore(); - } - break; - - case Qt::Key_A: - if( _ke->modifiers() & Qt::ControlModifier ) - { - m_selectButton->setChecked( TRUE ); - selectAll(); - update(); - } - else - { - _ke->ignore(); - } - break; - - case Qt::Key_D: - m_drawButton->setChecked( TRUE ); - break; - - case Qt::Key_E: - m_eraseButton->setChecked( TRUE ); - break; - - case Qt::Key_S: - m_selectButton->setChecked( TRUE ); - break; - - case Qt::Key_M: - m_moveButton->setChecked( TRUE ); - break; - - case Qt::Key_Delete: - deleteSelectedNotes(); - break; - - case Qt::Key_Space: - if( songEditor::inst()->playing() ) - { - stop(); - } - else - { - play(); - } - break; - - case Qt::Key_Home: - m_timeLine->pos().setTact( 0 ); - m_timeLine->pos().setTact64th( 0 ); - m_timeLine->updatePosition(); - break; - - default: - _ke->ignore(); - break; + const QPixmap * cursor = NULL; + // draw current edit-mode-icon below the cursor + switch( m_editMode ) + { + case DRAW: cursor = s_toolDraw; break; + case ERASE: cursor = s_toolErase; break; + case SELECT: cursor = s_toolSelect; break; + case MOVE: cursor = s_toolMove; break; + } + p.drawPixmap( mapFromGlobal( QCursor::pos() ) + QPoint( 8, 8 ), + *cursor ); } + +#ifndef QT4 + // and blit all the drawn stuff on the screen... + bitBlt( this, rect().topLeft(), &draw_pm ); +#endif +} + + + + +// responsible for moving/resizing scrollbars after window-resizing +void pianoRoll::resizeEvent( QResizeEvent * ) +{ + + m_leftRightScroll->setGeometry( WHITE_KEY_WIDTH, height() - + SCROLLBAR_SIZE, + width()-WHITE_KEY_WIDTH, + SCROLLBAR_SIZE ); + m_topBottomScroll->setGeometry( width() - SCROLLBAR_SIZE, PR_TOP_MARGIN, + SCROLLBAR_SIZE, + height() - PR_TOP_MARGIN - + SCROLLBAR_SIZE ); + + int total_pixels = OCTAVE_HEIGHT * OCTAVES - ( height() - + PR_TOP_MARGIN - PR_BOTTOM_MARGIN - + m_notesEditHeight ); + m_totalKeysToScroll = total_pixels * NOTES_PER_OCTAVE / OCTAVE_HEIGHT; + + m_topBottomScroll->setRange( 0, m_totalKeysToScroll ); +#ifdef QT4 + m_topBottomScroll->setSingleStep( 1 ); + m_topBottomScroll->setPageStep( 20 ); +#else + m_topBottomScroll->setSteps( 1, 20 ); +#endif + + if( m_startKey > m_totalKeysToScroll ) + { + m_startKey = m_totalKeysToScroll; + } + m_topBottomScroll->setValue( m_totalKeysToScroll - m_startKey ); + + songEditor::inst()->getPlayPos( songEditor::PLAY_PATTERN + ).m_timeLine->setFixedWidth( width() ); + m_toolBar->setFixedWidth( width() ); } @@ -1945,6 +1970,30 @@ void pianoRoll::wheelEvent( QWheelEvent * _we ) +int pianoRoll::getKey( int _y ) +{ + int key_line_y = height() - PR_BOTTOM_MARGIN - m_notesEditHeight - 1; + // pressed key on piano + int key_num = ( key_line_y - _y ) / KEY_LINE_HEIGHT; + key_num += m_startKey; + + // some range-checking-stuff + if( key_num < 0 ) + { + key_num = 0; + } + + if( key_num >= NOTES_PER_OCTAVE * OCTAVES ) + { + key_num = NOTES_PER_OCTAVE * OCTAVES - 1; + } + + return( m_lastKey = key_num ); +} + + + + void pianoRoll::play( void ) { if( validPattern() == FALSE ) @@ -2218,6 +2267,10 @@ void pianoRoll::copySelectedNotes( void ) m_notesToCopy.back()->setPos( m_notesToCopy.back()->pos( start_pos ) ); } + textFloat::displayMessage( tr( "Notes copied" ), + tr( "All selected notes were copied to the " + "clipboard." ), + embed::getIconPixmap( "edit_copy" ), 2000 ); } } diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp index b66fde8d52..b6c4128157 100644 --- a/src/core/plugin.cpp +++ b/src/core/plugin.cpp @@ -1,7 +1,7 @@ /* - * plugin.cpp - implemenation of plugin-class including plugin-loader + * plugin.cpp - implementation of plugin-class including plugin-loader * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -46,12 +46,29 @@ #include "dummy_plugin.h" +static embed::descriptor dummy_embed = { 0, NULL, "" } ; -plugin::plugin( const QString & _public_name, pluginTypes _type ) : - settings(), - m_publicName( _public_name ), - m_type( _type ) +static plugin::descriptor dummy_plugin_descriptor = { + "dummy", + "dummy", + QT_TRANSLATE_NOOP( "pluginBrowser", "no description" ), + "Tobias Doerffel ", + 0x0100, + plugin::UNDEFINED, + dummy_embed +} ; + + + +plugin::plugin( const descriptor * _descriptor ) : + settings(), + m_descriptor( _descriptor ) +{ + if( m_descriptor == NULL ) + { + m_descriptor = &dummy_plugin_descriptor; + } } @@ -89,7 +106,8 @@ plugin * plugin::instantiate( const QString & _plugin_name, void * _data ) ascii() #endif , RTLD_NOW );*/ - QLibrary plugin_lib( _plugin_name ); + QLibrary plugin_lib( configManager::inst()->pluginDir() + + _plugin_name ); if( /*handle == NULL*/ plugin_lib.load() == FALSE ) { QMessageBox::information( NULL, diff --git a/src/core/preset_preview_play_handle.cpp b/src/core/preset_preview_play_handle.cpp index 9295173629..db147f6c1c 100644 --- a/src/core/preset_preview_play_handle.cpp +++ b/src/core/preset_preview_play_handle.cpp @@ -99,7 +99,7 @@ QMutex * presetPreviewPlayHandle::s_globalDataMutex = NULL; presetPreviewPlayHandle::presetPreviewPlayHandle( const QString & _preset_file ) : - playHandle(), + playHandle( PRESET_PREVIEW_PLAY_HANDLE ), m_previewNote( NULL ) { if( s_globalDataMutex == NULL ) diff --git a/src/core/sample_play_handle.cpp b/src/core/sample_play_handle.cpp index 9e50e31f24..34be21d06e 100644 --- a/src/core/sample_play_handle.cpp +++ b/src/core/sample_play_handle.cpp @@ -36,7 +36,7 @@ samplePlayHandle::samplePlayHandle( const QString & _sample_file ) : - playHandle(), + playHandle( SAMPLE_PLAY_HANDLE ), m_sampleBuffer( new sampleBuffer( _sample_file ) ), m_ownSampleBuffer( TRUE ), m_doneMayReturnTrue( TRUE ), @@ -49,7 +49,7 @@ samplePlayHandle::samplePlayHandle( const QString & _sample_file ) : samplePlayHandle::samplePlayHandle( sampleBuffer * _sample_buffer ) : - playHandle(), + playHandle( SAMPLE_PLAY_HANDLE ), m_sampleBuffer( _sample_buffer ), m_ownSampleBuffer( FALSE ), m_doneMayReturnTrue( TRUE ), diff --git a/src/core/song_editor.cpp b/src/core/song_editor.cpp index 8ba1bcd3f6..fdf5a93a55 100644 --- a/src/core/song_editor.cpp +++ b/src/core/song_editor.cpp @@ -1269,8 +1269,11 @@ void songEditor::addSampleTrack( void ) float songEditor::framesPerTact( void ) const { + // when fooling around with tempo while playing, we sometimes get + // 0 here which leads to FP-exception, so handle it separately + const int bpm = tMax( 1, m_bpmSpinBox->value() ); return( mixer::inst()->sampleRate() * 60.0f * BEATS_PER_TACT / - m_bpmSpinBox->value() ); + bpm ); } @@ -1348,7 +1351,7 @@ void songEditor::clearProject( void ) // make sure all running notes are cleared, otherwise the whole // thing will end up in a SIGSEGV... - //mixer::inst()->clear(); + mixer::inst()->clear( TRUE ); while( mixer::inst()->haveNoRunningNotes() == FALSE ) { #ifdef QT4 @@ -1508,17 +1511,15 @@ bool songEditor::saveProject( void ) multimediaProject mmp( multimediaProject::SONG_PROJECT ); QDomElement bpm = mmp.createElement( "bpm" ); - bpm.setAttribute( "value", QString::number( m_bpmSpinBox->value() ) ); + bpm.setAttribute( "value", m_bpmSpinBox->value() ); mmp.head().appendChild( bpm ); QDomElement mv = mmp.createElement( "mastervol" ); - mv.setAttribute( "value", QString::number( 200 - - m_masterVolumeSlider->value() ) ); + mv.setAttribute( "value", 200 - m_masterVolumeSlider->value() ); mmp.head().appendChild( mv ); QDomElement mp = mmp.createElement( "masterpitch" ); - mp.setAttribute( "value", QString::number( - m_masterPitchSlider->value() ) ); + mp.setAttribute( "value", m_masterPitchSlider->value() ); mmp.head().appendChild( mp ); diff --git a/src/core/track.cpp b/src/core/track.cpp index 11f41c2554..ef189bc205 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -2,7 +2,7 @@ * track.cpp - implementation of classes concerning tracks -> neccessary for * all track-like objects (beat/bassline, sample-track...) * - * Copyright (c) 2004-2005 Tobias Doerffel + * Copyright (c) 2004-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -43,6 +43,9 @@ #include #include +#define setChecked setOn +#define isChecked isOn + #endif @@ -140,8 +143,8 @@ void trackContentObject::movePosition( const midiTime & _pos ) } m_startPosition = _pos; m_track->getTrackWidget()->changePosition(); - // moving of TCO can result in change of song-length etc., - // therefore we update the trackcontainer + // moving a TCO can result in change of song-length etc., + // therefore we update the track-container m_track->getTrackContainer()->update(); } @@ -156,7 +159,7 @@ void trackContentObject::changeLength( const midiTime & _length ) } m_length = _length; setFixedWidth( static_cast( m_length * pixelsPerTact() / 64 ) + - TCO_BORDER_WIDTH*2 ); + TCO_BORDER_WIDTH * 2 ); // changing length of TCO can result in change of song-length etc., // therefore we update the trackcontainer m_track->getTrackContainer()->update(); @@ -286,7 +289,7 @@ void trackContentObject::mousePressEvent( QMouseEvent * _me ) void trackContentObject::mouseMoveEvent( QMouseEvent * _me ) { const float ppt = m_track->getTrackContainer()->pixelsPerTact(); - if( m_moving ) + if( m_moving == TRUE ) { int x = mapToParent( _me->pos() ).x() - m_initialMouseX; movePosition( tMax( 0, (Sint32) m_track->getTrackContainer()-> @@ -299,13 +302,17 @@ void trackContentObject::mouseMoveEvent( QMouseEvent * _me ) s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) + QPoint( -2 - s_textFloat->width(), 8 ) ); } - else if( m_resizing ) + else if( m_resizing == TRUE ) { changeLength( tMax( 64, static_cast( _me->x() * 64 / ppt ) ) ); - s_textFloat->setText( QString( "%1:%2" ). - arg( length().getTact() + 1 ). - arg( length().getTact64th() ) ); + s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ). + arg( length().getTact() ). + arg( length().getTact64th() ). + arg( m_startPosition.getTact() + 1 ). + arg( m_startPosition.getTact64th() ). + arg( endPosition().getTact() + 1 ). + arg( endPosition().getTact64th() ) ); s_textFloat->move( mapTo( topLevelWidget(), QPoint( 0, 0 ) ) + QPoint( width() + 2, 8 ) ); } @@ -712,113 +719,47 @@ midiTime trackContentWidget::getPosition( int _mouse_x ) // =========================================================================== -// trackSettingsWidget +// trackOperationsWidget // =========================================================================== -trackSettingsWidget::trackSettingsWidget( trackWidget * _parent ) : + +QPixmap * trackOperationsWidget::s_grip = NULL; + + +trackOperationsWidget::trackOperationsWidget( trackWidget * _parent ) : QWidget( _parent ), m_trackWidget( _parent ) { -} - - - - -trackSettingsWidget::~trackSettingsWidget() -{ -} - - - - -void trackSettingsWidget::mousePressEvent( QMouseEvent * _me ) -{ - if( _me->button() == Qt::LeftButton && - m_trackWidget->getTrack()->type() != track::BB_TRACK ) + if( s_grip == NULL ) { - multimediaProject mmp( multimediaProject::DRAG_N_DROP_DATA ); - m_trackWidget->getTrack()->saveSettings( mmp, mmp.content() ); - new stringPairDrag( "track_" + - QString::number( m_trackWidget->getTrack()->type() ), - mmp.toString(), QPixmap::grabWidget( this ), this ); + s_grip = new QPixmap( embed::getIconPixmap( + "track_op_grip" ) ); } -} + + toolTip::add( this, tr( "Press while clicking on move-grip " + "to begin a new drag'n'drop-action" ) ); + + QMenu * to_menu = new QMenu( this ); + to_menu->setFont( pointSize<9>( to_menu->font() ) ); + to_menu->addAction( embed::getIconPixmap( "edit_copy", 16, 16 ), + tr( "Clone this track" ), + this, SLOT( cloneTrack() ) ); + to_menu->addAction( embed::getIconPixmap( "cancel", 16, 16 ), + tr( "Remove this track" ), + this, SLOT( removeTrack() ) ); + m_trackOps = new QPushButton( embed::getIconPixmap( "track_op_menu" ), + "", this ); + m_trackOps->setGeometry( 12, 1, 28, 28 ); + m_trackOps->setMenu( to_menu ); + toolTip::add( m_trackOps, tr( "Operations for this track" ) ); - - -// =========================================================================== -// trackWidget -// =========================================================================== - -trackWidget::trackWidget( track * _track, QWidget * _parent ) : - QWidget( _parent ), - m_track( _track ), - m_trackOperationsWidget( this ), - m_trackSettingsWidget( this ), - m_trackContentWidget( this ) -{ -#ifdef QT4 - { - QPalette pal; - pal.setColor( m_trackOperationsWidget.backgroundRole(), - QColor( 128, 128, 128 ) ); - m_trackOperationsWidget.setPalette( pal ); - } -#else - m_trackOperationsWidget.setPaletteBackgroundColor( - QColor( 128, 128, 128 ) ); -#endif - - - QPushButton * clntr_btn = new QPushButton( embed::getIconPixmap( - "edit_copy", 12, 12 ), - "", - &m_trackOperationsWidget ); - clntr_btn->setGeometry( 1, 1, TRACK_OP_BTN_WIDTH, TRACK_OP_BTN_HEIGHT ); - connect( clntr_btn, SIGNAL( clicked() ), this, SLOT( cloneTrack() ) ); - connect( clntr_btn, SIGNAL( clicked() ), clntr_btn, - SLOT( clearFocus() ) ); - toolTip::add( clntr_btn, tr( "Clone this track" ) ); - - QPushButton * deltr_btn = new QPushButton( embed::getIconPixmap( - "cancel", 12, 12 ), - "", &m_trackOperationsWidget ); - deltr_btn->setGeometry( 1, 1+TRACK_OP_BTN_HEIGHT, TRACK_OP_BTN_WIDTH, - TRACK_OP_BTN_HEIGHT ); - connect( deltr_btn, SIGNAL( clicked() ), this, SLOT( removeTrack() ) ); - connect( deltr_btn, SIGNAL( clicked() ), deltr_btn, - SLOT( clearFocus() ) ); - toolTip::add( deltr_btn, tr( "Remove this track" ) ); - - QPushButton * muptr_btn = new QPushButton( embed::getIconPixmap( - "arp_up_on", 12, 12 ), - "", &m_trackOperationsWidget ); - muptr_btn->setGeometry( 1+TRACK_OP_BTN_WIDTH, 1, TRACK_OP_BTN_WIDTH, - TRACK_OP_BTN_HEIGHT ); - connect( muptr_btn, SIGNAL( clicked() ), this, SLOT( moveTrackUp() ) ); - connect( muptr_btn, SIGNAL( clicked() ), muptr_btn, - SLOT( clearFocus() ) ); - toolTip::add( muptr_btn, tr( "Move this track up" ) ); - - QPushButton * mdowntr_btn = new QPushButton( embed::getIconPixmap( - "arp_down_on", 12, 12 ), - "", &m_trackOperationsWidget ); - mdowntr_btn->setGeometry( 1+TRACK_OP_BTN_WIDTH, 1+TRACK_OP_BTN_HEIGHT, - TRACK_OP_BTN_WIDTH, - TRACK_OP_BTN_HEIGHT ); - connect( mdowntr_btn, SIGNAL( clicked() ), this, - SLOT( moveTrackDown() ) ); - connect( mdowntr_btn, SIGNAL( clicked() ), mdowntr_btn, - SLOT( clearFocus() ) ); - toolTip::add( mdowntr_btn, tr( "Move this track down" ) ); - - m_muteBtn = new pixmapButton( &m_trackOperationsWidget ); + m_muteBtn = new pixmapButton( this ); m_muteBtn->setActiveGraphic( embed::getIconPixmap( "mute_on" ) ); m_muteBtn->setInactiveGraphic( embed::getIconPixmap( "mute_off" ) ); - m_muteBtn->move( 3+TRACK_OP_BTN_WIDTH*2, 8 ); + m_muteBtn->move( 44, 8 ); m_muteBtn->show(); connect( m_muteBtn, SIGNAL( toggled( bool ) ), this, SLOT( setMuted( bool ) ) ); @@ -839,20 +780,167 @@ trackWidget::trackWidget( track * _track, QWidget * _parent ) : "this track." ) ); toolTip::add( m_muteBtn, tr( "left click = mute this track\n" "right click = mute all other tracks (solo)" ) ); +} + + +trackOperationsWidget::~trackOperationsWidget() +{ +} + + + + +bool trackOperationsWidget::muted( void ) const +{ + return( m_muteBtn->isChecked() ); +} + + + + +void trackOperationsWidget::mousePressEvent( QMouseEvent * _me ) +{ + if( _me->button() == Qt::LeftButton && + lmmsMainWin::isCtrlPressed() == TRUE && + m_trackWidget->getTrack()->type() != track::BB_TRACK ) + { + multimediaProject mmp( multimediaProject::DRAG_N_DROP_DATA ); + m_trackWidget->getTrack()->saveSettings( mmp, mmp.content() ); + new stringPairDrag( "track_" + + QString::number( m_trackWidget->getTrack()->type() ), + mmp.toString(), QPixmap::grabWidget( + &m_trackWidget->getTrackSettingsWidget() ), + this ); + } + else if( _me->button() == Qt::LeftButton && _me->x() < 10 ) + { + // track-widget (parent-widget) initiates track-move + _me->ignore(); + } +} + + + + + +void trackOperationsWidget::paintEvent( QPaintEvent * _pe ) +{ +#ifdef QT4 + QPainter p( this ); + p.fillRect( rect(), QColor( 128, 128, 128 ) ); +#else + // create pixmap for whole widget + QPixmap pm( rect().size() ); + pm.fill( QColor( 128, 128, 128 ) ); + + // and a painter for it + QPainter p( &pm ); +#endif + if( m_trackWidget->isMovingTrack() == FALSE ) + { + p.drawPixmap( 2, 2, *s_grip ); +/* if( m_trackOps->isVisible() == FALSE ) + {*/ + m_trackOps->show(); +/* } + if( m_muteBtn->isVisible() == FALSE ) + {*/ + m_muteBtn->show(); +// } + } + else + { + m_trackOps->hide(); + m_muteBtn->hide(); + } + +#ifndef QT4 + // blit drawn pixmap to actual widget + bitBlt( this, rect().topLeft(), &pm ); +#endif +} + + + + +void trackOperationsWidget::cloneTrack( void ) +{ + m_trackWidget->getTrack()->getTrackContainer()->cloneTrack( + m_trackWidget->getTrack() ); +} + + + + +void trackOperationsWidget::removeTrack( void ) +{ + m_trackWidget->getTrack()->getTrackContainer()->removeTrack( + m_trackWidget->getTrack() ); +} + + + + +void trackOperationsWidget::setMuted( bool _muted ) +{ + m_muteBtn->setChecked( _muted ); + m_trackWidget->getTrackContentWidget().updateTCOs(); +} + + + + +void trackOperationsWidget::muteBtnRightClicked( void ) +{ + const bool m = muted(); // next function might modify our mute-state, + // so save it + m_trackWidget->getTrack()->getTrackContainer()->setMutedOfAllTracks( + m ); + setMuted( !m ); +} + + + + + + +// =========================================================================== +// trackWidget +// =========================================================================== + +trackWidget::trackWidget( track * _track, QWidget * _parent ) : + QWidget( _parent ), + m_track( _track ), + m_trackOperationsWidget( this ), + m_trackSettingsWidget( this ), + m_trackContentWidget( this ), + m_movingTrack( FALSE ), + m_initialMouseX( -1 ) +{ #ifdef QT4 { QPalette pal; - pal.setColor( m_trackSettingsWidget.backgroundRole(), - QColor( 64, 64, 64 ) ); - m_trackSettingsWidget.setPalette( pal ); + pal.setColor( m_trackOperationsWidget.backgroundRole(), + QColor( 128, 128, 128 ) ); + m_trackOperationsWidget.setPalette( pal ); } #else - m_trackSettingsWidget.setPaletteBackgroundColor( QColor( 64, 64, 64 ) ); + m_trackOperationsWidget.setPaletteBackgroundColor( + QColor( 128, 128, 128 ) ); #endif + + + +#ifdef QT4 + QPalette pal; + pal.setColor( m_trackSettingsWidget.backgroundRole(), + QColor( 64, 64, 64 ) ); + m_trackSettingsWidget.setPalette( pal ); +#else + m_trackSettingsWidget.setPaletteBackgroundColor( QColor( 64, 64, 64 ) ); // set background-mode for flicker-free redraw -#ifndef QT4 setBackgroundMode( Qt::NoBackground ); #endif setAcceptDrops( TRUE ); @@ -869,18 +957,6 @@ trackWidget::~trackWidget() -bool trackWidget::muted( void ) const -{ -#ifdef QT4 - return( m_muteBtn->isChecked() ); -#else - return( m_muteBtn->isOn() ); -#endif -} - - - - // resposible for moving track-content-widgets to appropriate position after // change of visible viewport void trackWidget::changePosition( const midiTime & _new_pos ) @@ -921,61 +997,6 @@ void trackWidget::changePosition( const midiTime & _new_pos ) -void trackWidget::cloneTrack( void ) -{ - m_track->getTrackContainer()->cloneTrack( m_track ); -} - - - - -void trackWidget::removeTrack( void ) -{ - m_track->getTrackContainer()->removeTrack( m_track ); -} - - - - -void trackWidget::moveTrackUp( void ) -{ - m_track->getTrackContainer()->moveTrackUp( m_track ); -} - - - - -void trackWidget::moveTrackDown( void ) -{ - m_track->getTrackContainer()->moveTrackDown( m_track ); -} - - - - -void trackWidget::setMuted( bool _muted ) -{ -#ifdef QT4 - m_muteBtn->setChecked( _muted ); -#else - m_muteBtn->setOn( _muted ); -#endif - m_trackContentWidget.updateTCOs(); -} - - - - -void trackWidget::muteBtnRightClicked( void ) -{ - bool m = muted(); - m_track->getTrackContainer()->setMutedOfAllTracks( m ); - setMuted( !m ); -} - - - - void trackWidget::dragEnterEvent( QDragEnterEvent * _dee ) { stringPairDrag::processDragEnterEvent( _dee, "track_" + @@ -1002,6 +1023,69 @@ void trackWidget::dropEvent( QDropEvent * _de ) +void trackWidget::mousePressEvent( QMouseEvent * _me ) +{ + if( _me->button() == Qt::LeftButton ) + { + m_movingTrack = TRUE; + m_initialMouseX = _me->x(); + + QCursor c( Qt::SizeAllCursor ); + QApplication::setOverrideCursor( c ); + + m_trackOperationsWidget.update(); + + _me->accept(); + } + else + { + QWidget::mousePressEvent( _me ); + } +} + + + + +void trackWidget::mouseMoveEvent( QMouseEvent * _me ) +{ + if( m_movingTrack == TRUE ) + { + trackContainer * tc = m_track->getTrackContainer(); + // look which track-widget the mouse-cursor is over + const trackWidget * track_at_y = tc->trackWidgetAt( + mapTo( tc->containerWidget(), _me->pos() ).y() ); + // a track-widget not equal to ourself? + if( track_at_y != NULL && track_at_y != this ) + { + // then move us up/down there! + if( _me->y() < 0 ) + { + tc->moveTrackUp( m_track ); + } + else + { + tc->moveTrackDown( m_track ); + } + } + } +} + + + + +void trackWidget::mouseReleaseEvent( QMouseEvent * _me ) +{ + m_movingTrack = FALSE; + while( QApplication::overrideCursor() != NULL ) + { + QApplication::restoreOverrideCursor(); + } + m_trackOperationsWidget.update(); +} + + + + void trackWidget::paintEvent( QPaintEvent * _pe ) { #ifdef QT4 @@ -1009,7 +1093,7 @@ void trackWidget::paintEvent( QPaintEvent * _pe ) #else // create pixmap for whole widget QPixmap pm( rect().size() ); - pm.fill( QColor( 128, 128, 128 ) ); + pm.fill( QColor( 224, 224, 224 ) ); // and a painter for it QPainter p( &pm ); @@ -1143,7 +1227,7 @@ void FASTCALL track::saveSettings( QDomDocument & _doc, QDomElement & _parent ) csize num_of_tcos = getTrackContentWidget()->numOfTCOs(); QDomElement track_de = _doc.createElement( "track" ); - track_de.setAttribute( "type", QString::number( type() ) ); + track_de.setAttribute( "type", type() ); track_de.setAttribute( "muted", muted() ); _parent.appendChild( track_de ); @@ -1170,7 +1254,7 @@ void FASTCALL track::loadSettings( const QDomElement & _this ) "settings-node!\n" ); } - m_trackWidget->setMuted( _this.attribute( "muted" ).toInt() ); + setMuted( _this.attribute( "muted" ).toInt() ); getTrackContentWidget()->removeAllTCOs(); @@ -1295,5 +1379,13 @@ void FASTCALL track::swapPositionOfTCOs( csize _tco_num1, csize _tco_num2 ) +#ifndef QT4 + +#undef isChecked +#undef setChecked + +#endif + + #include "track.moc" diff --git a/src/core/track_container.cpp b/src/core/track_container.cpp index 0e79976e4f..b6458eb5b5 100644 --- a/src/core/track_container.cpp +++ b/src/core/track_container.cpp @@ -57,6 +57,7 @@ #include "mmp.h" #include "config_mgr.h" #include "midi_file.h" +#include "instrument.h" @@ -304,6 +305,25 @@ void trackContainer::realignTracks( bool _complete_update ) +const trackWidget * trackContainer::trackWidgetAt( const int _y ) const +{ + int y_cnt = 0; + for( trackWidgetVector::const_iterator it = m_trackWidgets.begin(); + it != m_trackWidgets.end(); ++it ) + { + const int y_cnt1 = y_cnt; + y_cnt += ( *it )->height(); + if( _y >= y_cnt1 && _y < y_cnt ) + { + return( *it ); + } + } + return( NULL ); +} + + + + unsigned int trackContainer::countTracks( track::trackTypes _tt ) const { unsigned int cnt = 0; @@ -327,7 +347,7 @@ void trackContainer::setMutedOfAllTracks( bool _muted ) for( trackWidgetVector::iterator it = m_trackWidgets.begin(); it != m_trackWidgets.end(); ++it ) { - ( *it )->setMuted( _muted ); + ( *it )->getTrack()->setMuted( _muted ); } } @@ -381,7 +401,8 @@ void trackContainer::resizeEvent( QResizeEvent * ) void trackContainer::dragEnterEvent( QDragEnterEvent * _dee ) { stringPairDrag::processDragEnterEvent( _dee, - QString( "presetfile,instrument,midifile,track_%1,track_%2" ). + QString( "presetfile,sampledata,samplefile,instrument,midifile," + "track_%1,track_%2" ). arg( track::CHANNEL_TRACK ). arg( track::SAMPLE_TRACK ) ); } @@ -402,6 +423,16 @@ void trackContainer::dropEvent( QDropEvent * _de ) ct->toggledChannelButton( TRUE ); _de->accept(); } + else if( type == "sampledata" || type == "samplefile" ) + { + channelTrack * ct = dynamic_cast( + track::create( track::CHANNEL_TRACK, + this ) ); + instrument * i = ct->loadInstrument( "audiofileprocessor" ); + i->setParameter( type, value ); + ct->toggledChannelButton( TRUE ); + _de->accept(); + } else if( type == "presetfile" ) { multimediaProject mmp( value ); diff --git a/src/lib/sample_buffer.cpp b/src/lib/sample_buffer.cpp index 48de355f3e..2289e91e2d 100644 --- a/src/lib/sample_buffer.cpp +++ b/src/lib/sample_buffer.cpp @@ -1,7 +1,7 @@ /* * sample_buffer.cpp - container-class sampleBuffer * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -159,6 +159,35 @@ sampleBuffer::sampleBuffer( const sampleFrame * _data, Uint32 _frames ) : +sampleBuffer::sampleBuffer( Uint32 _frames ) : + QObject(), + m_audioFile( "" ), + m_origData( NULL ), + m_origFrames( 0 ), + m_data( NULL ), + m_frames( 0 ), + m_startFrame( 0 ), + m_endFrame( 0 ), + m_amplification( 1.0f ), + m_reversed( FALSE ), + m_dataMutex() +{ + m_origData = new sampleFrame[_frames]; + memset( m_origData, 0, _frames * BYTES_PER_FRAME ); + m_origFrames = _frames; +#ifdef SDL_SDL_SOUND_H + // init sound-file-system of SDL + Sound_Init(); +#endif +#ifdef HAVE_SAMPLERATE_H + initResampling(); +#endif + update(); +} + + + + sampleBuffer::~sampleBuffer() { m_dataMutex.lock(); @@ -166,11 +195,12 @@ sampleBuffer::~sampleBuffer() m_origData = NULL; delete[] m_data; m_data = NULL; - m_dataMutex.unlock(); #ifdef HAVE_SAMPLERATE_H quitResampling(); #endif + + m_dataMutex.unlock(); } @@ -223,45 +253,36 @@ void sampleBuffer::update( bool _keep_settings ) file.ascii(); #endif Sint16 * buf = NULL; - Uint8 channels; + Uint8 channels = DEFAULT_CHANNELS; + Uint32 samplerate = SAMPLE_RATES[DEFAULT_QUALITY_LEVEL]; #ifdef HAVE_SNDFILE_H if( m_frames == 0 ) { - m_frames = decodeSampleSF( f, buf, channels ); - } -#endif -#ifdef SDL_SDL_SOUND_H - if( m_frames == 0 ) - { - m_frames = decodeSampleSDL( f, buf, channels ); + m_frames = decodeSampleSF( f, buf, channels, + samplerate ); } #endif #ifdef HAVE_VORBIS_VORBISFILE_H if( m_frames == 0 ) { - m_frames = decodeSampleOGG( f, buf, channels ); + m_frames = decodeSampleOGGVorbis( f, buf, channels, + samplerate ); + } +#endif +#ifdef SDL_SDL_SOUND_H + if( m_frames == 0 ) + { + m_frames = decodeSampleSDL( f, buf, channels, + samplerate ); } #endif if( m_frames > 0 && buf != NULL ) { - if( _keep_settings == FALSE ) - { - // update frame-variables - m_startFrame = 0; - if( m_frames > 0 ) - { - m_endFrame = m_frames - 1; - } - else - { - m_endFrame = 0; - } - } - // following code transforms int-samples into // float-samples and does amplifying & reversing - float fac = m_amplification / 32767.0f; + const float fac = m_amplification / + OUTPUT_SAMPLE_MULTIPLIER; m_data = new sampleFrame[m_frames]; // if reversing is on, we also reverse when @@ -297,9 +318,39 @@ m_data[frame][chnl] = buf[idx] * fac; delete[] buf; + // do samplerate-conversion if sample-decoder didn't + // convert sample-rate to our default-samplerate + if( samplerate != SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] ) + { + sampleBuffer * resampled = resample( this, + samplerate, + SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] ); + delete[] m_data; + m_frames = resampled->frames(); + m_data = new sampleFrame[m_frames]; + memcpy( m_data, resampled->data(), m_frames * + sizeof( sampleFrame ) ); + delete resampled; + } + + if( _keep_settings == FALSE ) + { + // update frame-variables + m_startFrame = 0; + if( m_frames > 0 ) + { + m_endFrame = m_frames - 1; + } + else + { + m_endFrame = 0; + } + } } else { + // sample couldn't be decoded, create buffer containing + // one sample-frame m_data = new sampleFrame[1]; memset( m_data, 0, sizeof( *m_data ) ); m_frames = 1; @@ -309,6 +360,8 @@ m_data[frame][chnl] = buf[idx] * fac; } else { + // neither an audio-file nor a buffer to copy from, so create + // buffer containing one sample-frame m_data = new sampleFrame[1]; memset( m_data, 0, sizeof( *m_data ) * 1 ); m_frames = 1; @@ -326,13 +379,14 @@ m_data[frame][chnl] = buf[idx] * fac; #ifdef SDL_SDL_SOUND_H Uint32 sampleBuffer::decodeSampleSDL( const char * _f, Sint16 * & _buf, - Uint8 & _channels ) + Uint8 & _channels, + Uint32 & _samplerate ) { Sound_AudioInfo STD_AUDIO_INFO = { AUDIO_S16SYS, - DEFAULT_CHANNELS, - SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] + _channels, + _samplerate, } ; Uint32 frames = 0; @@ -343,7 +397,8 @@ Uint32 sampleBuffer::decodeSampleSDL( const char * _f, Sint16 * & _buf, { // let SDL_sound decode our file to requested format ( void )Sound_DecodeAll( snd_sample ); - _channels = STD_AUDIO_INFO.channels; + _channels = snd_sample->actual.channels; + _samplerate = snd_sample->actual.rate; frames = snd_sample->buffer_size / ( BYTES_PER_OUTPUT_SAMPLE * _channels ); _buf = new Sint16[frames * _channels]; @@ -360,7 +415,8 @@ Uint32 sampleBuffer::decodeSampleSDL( const char * _f, Sint16 * & _buf, #ifdef HAVE_SNDFILE_H Uint32 sampleBuffer::decodeSampleSF( const char * _f, Sint16 * & _buf, - Uint8 & _channels ) + Uint8 & _channels, + Uint32 & _samplerate ) { SNDFILE * snd_file; SF_INFO sf_info; @@ -377,6 +433,7 @@ Uint32 sampleBuffer::decodeSampleSF( const char * _f, Sint16 * & _buf, _buf = new Sint16[sf_info.channels * frames]; frames = sf_read_short( snd_file, _buf, frames ); _channels = sf_info.channels; + _samplerate = sf_info.samplerate; sf_close( snd_file ); } @@ -384,7 +441,7 @@ Uint32 sampleBuffer::decodeSampleSF( const char * _f, Sint16 * & _buf, { #ifdef DEBUG_LMMS printf( "sampleBuffer::decodeSampleSF(): could not load " - "sample %s: %s\n", _f, sf_strerror( NULL ) ); + "sample %s: %s\n", _f, sf_strerror( NULL ) ); #endif } return( frames ); @@ -398,9 +455,6 @@ Uint32 sampleBuffer::decodeSampleSF( const char * _f, Sint16 * & _buf, // callback-functions for reading ogg-file -#ifndef QT4 -#endif - size_t qfileReadCallback( void * _ptr, size_t _size, size_t _n, void * _udata ) { return( static_cast( _udata )->read( (char*)_ptr, @@ -449,8 +503,9 @@ long qfileTellCallback( void * _udata ) -Uint32 sampleBuffer::decodeSampleOGG( const char * _f, Sint16 * & _buf, - Uint8 & _channels ) +Uint32 sampleBuffer::decodeSampleOGGVorbis( const char * _f, Sint16 * & _buf, + Uint8 & _channels, + Uint32 & _samplerate ) { static ov_callbacks callbacks = { @@ -482,20 +537,20 @@ Uint32 sampleBuffer::decodeSampleOGG( const char * _f, Sint16 * & _buf, switch( err ) { case OV_EREAD: - printf( "sampleBuffer::decodeSampleOgg(): " - "media read error\n" ); + printf( "sampleBuffer::decodeSampleOGGVorbis():" + " media read error\n" ); break; case OV_ENOTVORBIS: - printf( "sampleBuffer::decodeSampleOgg(): " - "not an Ogg Vorbis file\n" ); +/* printf( "sampleBuffer::decodeSampleOGGVorbis():" + " not an Ogg Vorbis file\n" );*/ break; case OV_EVERSION: - printf( "sampleBuffer::decodeSampleOgg(): " - "vorbis version mismatch\n" ); + printf( "sampleBuffer::decodeSampleOGGVorbis():" + " vorbis version mismatch\n" ); break; case OV_EBADHEADER: - printf( "sampleBuffer::decodeSampleOgg(): " - "invalid Vorbis bitstream header\n" ); + printf( "sampleBuffer::decodeSampleOGGVorbis():" + " invalid Vorbis bitstream header\n" ); break; case OV_EFAULT: printf( "sampleBuffer::decodeSampleOgg(): " @@ -509,6 +564,8 @@ Uint32 sampleBuffer::decodeSampleOGG( const char * _f, Sint16 * & _buf, ov_pcm_seek( &vf, 0 ); _channels = ov_info( &vf, -1 )->channels; + _samplerate = ov_info( &vf, -1 )->rate; + ogg_int64_t total = ov_pcm_total( &vf, -1 ); _buf = new Sint16[total * _channels]; @@ -517,7 +574,7 @@ Uint32 sampleBuffer::decodeSampleOGG( const char * _f, Sint16 * & _buf, do { - bytes_read = ov_read( &vf, (char *)&_buf[frames * _channels], + bytes_read = ov_read( &vf, (char *) &_buf[frames * _channels], ( total - frames ) * _channels * sizeof( Sint16 ), isLittleEndian()? 0 : 1, @@ -694,7 +751,7 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab, Uint32 _start_frame, total_frames_for_current_pitch; } - const float src_frame_idx = frame*freq_factor; + const float src_frame_idx = frame * freq_factor; Uint32 frame_num = static_cast( src_frame_idx) - src_frame_base; const float frac_pos = src_frame_idx - @@ -912,35 +969,35 @@ QString sampleBuffer::openAudioFile( void ) const // set filters #ifdef QT4 QStringList types; - types << tr( "All Audio-Files (*.wav *.ogg *.voc *.aif *.aiff *.au " - "*.raw)" ) + types << tr( "All Audio-Files (*.wav *.ogg *.flac *.voc *.aif *.aiff " + "*.au *.raw)" ) << tr( "Wave-Files (*.wav)" ) << tr( "OGG-Files (*.ogg)" ) + << tr( "FLAC-Files (*.flac)" ) //<< tr( "MP3-Files (*.mp3)" ) //<< tr( "MIDI-Files (*.mid)" ) << tr( "VOC-Files (*.voc)" ) << tr( "AIFF-Files (*.aif *.aiff)" ) << tr( "AU-Files (*.au)" ) << tr( "RAW-Files (*.raw)" ) - //<< tr( "FLAC-Files (*.flac)" ) //<< tr( "MOD-Files (*.mod)" ) ; ofd.setFilters( types ); #else - ofd.addFilter( tr( "All Audio-Files (*.wav *.ogg *.voc *.aif *.aiff " - "*.au *.raw)" ) ); + ofd.addFilter( tr( "All Audio-Files (*.wav *.ogg *.flac *.voc *.aif " + "*.aiff *.au *.raw)" ) ); ofd.addFilter( tr( "Wave-Files (*.wav)" ) ); ofd.addFilter( tr( "OGG-Files (*.ogg)" ) ); + ofd.addFilter( tr( "FLAC-Files (*.flac)" ) ); //ofd.addFilter (tr("MP3-Files (*.mp3)")); - //ofd.addFilter (tr("MIDI-Files (*.mid)")); + //ofd.addFilter (tr("MIDI-Files (*.mid)"));^ ofd.addFilter( tr( "VOC-Files (*.voc)" ) ); ofd.addFilter( tr( "AIFF-Files (*.aif *.aiff)" ) ); ofd.addFilter( tr( "AU-Files (*.au)" ) ); ofd.addFilter( tr( "RAW-Files (*.raw)" ) ); - //ofd.addFilter (tr("FLAC-Files (*.flac)")); //ofd.addFilter (tr("MOD-Files (*.mod)")); - ofd.setSelectedFilter( tr( "All Audio-Files (*.wav *.ogg *.voc *.aif " - "*.aiff *.au *.raw)" ) ); + ofd.setSelectedFilter( tr( "All Audio-Files (*.wav *.ogg *.flac *.voc " + "*.aif *.aiff *.au *.raw)" ) ); #endif if( m_audioFile != "" ) { @@ -1016,6 +1073,8 @@ QString sampleBuffer::toBase64( void ) const { return( "" ); } + // the following code is quite confusing as we have to handle four + // different configs (no flac/qt3, no flac/qt4, flac/qt3, flac/qt4) #ifdef HAVE_FLAC_STREAM_ENCODER_H const Uint32 FRAMES_PER_BUF = 1152; @@ -1155,6 +1214,69 @@ QString sampleBuffer::toBase64( void ) const +sampleBuffer * sampleBuffer::resample( sampleFrame * _data, + const Uint32 _frames, + const Uint32 _src_sr, + const Uint32 _dst_sr ) +{ + const Uint32 dst_frames = static_cast( _frames / + (float) _src_sr * (float) _dst_sr ); + sampleBuffer * dst_sb = new sampleBuffer( dst_frames ); + sampleFrame * dst_buf = dst_sb->m_origData; +#ifdef HAVE_SAMPLERATE_H + // yeah, libsamplerate, let's rock with sinc-interpolation! + int error; + SRC_STATE * state; + if( ( state = src_new( SRC_SINC_MEDIUM_QUALITY, + DEFAULT_CHANNELS, &error ) ) != NULL ) + { + SRC_DATA src_data; + src_data.end_of_input = 0; + src_data.data_in = _data[0]; + src_data.data_out = dst_buf[0]; + src_data.input_frames = _frames; + src_data.output_frames = dst_frames; + src_data.src_ratio = (float) _dst_sr / _src_sr; + int error; + if( ( error = src_process( state, &src_data ) ) ) + { + printf( "sampleBuffer: error while resampling: %s\n", + src_strerror( error ) ); + } + src_delete( state ); + } + else + { + printf( "Error: src_new() failed in sample_buffer.cpp!\n" ); + } +#else + // no libsamplerate, so do simple cubic interpolation + for( Uint32 frame = 0; frame < dst_frames; ++frame ) + { + const float src_frame_float = frame * (float) _src_sr / _dst_sr; + const float frac_pos = src_frame_float - + static_cast( src_frame_float ); + const Uint32 src_frame = tLimit( + static_cast( src_frame_float ), + 1, _frames - 2 ); + for( Uint8 ch = 0; ch < DEFAULT_CHANNELS; ++ch ) + { + dst_buf[frame][ch] = cubicInterpolate( + _data[src_frame - 1][ch], + _data[src_frame + 0][ch], + _data[src_frame + 1][ch], + _data[src_frame + 2][ch], + frac_pos ); + } + } +#endif + dst_sb->update(); + return( dst_sb ); +} + + + + void sampleBuffer::setAudioFile( const QString & _audio_file ) { m_audioFile = _audio_file; @@ -1375,6 +1497,7 @@ void sampleBuffer::loadFromBase64( const QString & _data ) delete[] m_origData; m_origData = new sampleFrame[m_origFrames]; memcpy( m_origData, orig_data.data(), orig_data.size() ); + m_audioFile = ""; update(); #ifndef QT4 // delete[] dst; diff --git a/src/lib/string_pair_drag.cpp b/src/lib/string_pair_drag.cpp index beb903cc6f..4346d7c649 100644 --- a/src/lib/string_pair_drag.cpp +++ b/src/lib/string_pair_drag.cpp @@ -1,8 +1,9 @@ /* * string_pair_drag.cpp - class stringPairDrag which provides general support - * for drag'n'drop of string-pairs + * for drag'n'drop of string-pairs and which is the base + * for all drag'n'drop-actions within LMMS * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -25,6 +26,7 @@ #include "string_pair_drag.h" +#include "lmms_main_win.h" #ifdef QT4 @@ -61,6 +63,9 @@ stringPairDrag::stringPairDrag( const QString & _key, const QString & _value, stringPairDrag::~stringPairDrag() { + // during a drag, we might have lost key-press-events, so reset + // modifiers of main-win + lmmsMainWin::inst()->clearKeyModifiers(); // TODO: do we have to delete anything??? } @@ -81,6 +86,7 @@ bool stringPairDrag::processDragEnterEvent( QDragEnterEvent * _dee, _dee->acceptProposedAction(); return( TRUE ); } + _dee->ignore(); return( FALSE ); #else QString txt = _dee->encodedData( "lmms/stringpair" ); diff --git a/src/tracks/bb_track.cpp b/src/tracks/bb_track.cpp index f379e13e86..a09713c1b9 100644 --- a/src/tracks/bb_track.cpp +++ b/src/tracks/bb_track.cpp @@ -62,7 +62,6 @@ bbTCO::bbTCO( track * _track, const QColor & _c ) : QString( "" ) ), m_color( _c.isValid() ? _c : QColor( 64, 128, 255 ) ) { - //setPaletteBackgroundColor( QColor( 64, 128, 255 ) ); #ifndef QT4 setBackgroundMode( Qt::NoBackground ); #endif @@ -84,24 +83,6 @@ bbTCO::~bbTCO() -void bbTCO::movePosition( const midiTime & _pos ) -{ - // bb-playlist-entries are always aligned at tact-boundaries - trackContentObject::movePosition( midiTime( _pos.getTact(), 0 ) ); -} - - - - -void bbTCO::changeLength( const midiTime & _length ) -{ - // the length of a bb-playlist-entry is always a multiple of one tact - trackContentObject::changeLength( midiTime( _length.getTact(), 0 ) ); -} - - - - void bbTCO::constructContextMenu( QMenu * _cm ) { #ifdef QT4 @@ -169,7 +150,6 @@ void bbTCO::paintEvent( QPaintEvent * ) p.setPen( col.light( 130 - y * 60 / height() ) ); p.drawLine( 1, y, width() - 1, y ); } - //pm.fill( col ); #endif tact t = bbEditor::inst()->lengthOfBB( bbTrack::numOfBBTrack( @@ -208,15 +188,14 @@ void bbTCO::saveSettings( QDomDocument & _doc, QDomElement & _parent ) bbtco_de.setAttribute( "name", m_name ); if( _parent.nodeName() == "clipboard" ) { - bbtco_de.setAttribute( "pos", QString::number( -1 ) ); + bbtco_de.setAttribute( "pos", -1 ); } else { - bbtco_de.setAttribute( "pos", - QString::number( startPosition() ) ); + bbtco_de.setAttribute( "pos", startPosition() ); } - bbtco_de.setAttribute( "len", QString::number( length() ) ); - bbtco_de.setAttribute( "color", QString::number( m_color.rgb() ) ); + bbtco_de.setAttribute( "len", length() ); + bbtco_de.setAttribute( "color", m_color.rgb() ); _parent.appendChild( bbtco_de ); } diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index 870a9a5e86..8ec9e5c305 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -397,7 +397,7 @@ void pattern::playFrozenData( sampleFrame * _ab, Uint32 _start_frame, void pattern::saveSettings( QDomDocument & _doc, QDomElement & _parent ) { QDomElement pattern_de = _doc.createElement( nodeName() ); - pattern_de.setAttribute( "type", QString::number( m_patternType ) ); + pattern_de.setAttribute( "type", m_patternType ); pattern_de.setAttribute( "name", m_name ); // as the target of copied/dragged pattern is always an existing // pattern, we must not store actual position, instead we store -1 @@ -405,16 +405,15 @@ void pattern::saveSettings( QDomDocument & _doc, QDomElement & _parent ) if( _parent.nodeName() == "clipboard" || _parent.nodeName() == "dnddata" ) { - pattern_de.setAttribute( "pos", QString::number( -1 ) ); + pattern_de.setAttribute( "pos", -1 ); } else { - pattern_de.setAttribute( "pos", QString::number( - startPosition() ) ); + pattern_de.setAttribute( "pos", startPosition() ); } - pattern_de.setAttribute( "len", QString::number( length() ) ); - pattern_de.setAttribute( "frozen", QString::number( - m_frozenPattern != NULL ) ); + pattern_de.setAttribute( "len", length() ); + pattern_de.setAttribute( "steps", m_steps ); + pattern_de.setAttribute( "frozen", m_frozenPattern != NULL ); _parent.appendChild( pattern_de ); // now save settings of all notes @@ -850,6 +849,11 @@ void pattern::wheelEvent( QWheelEvent * _we ) } songEditor::inst()->setModified(); update(); + _we->accept(); + } + else + { + trackContentObject::wheelEvent( _we ); } } diff --git a/src/tracks/sample_track.cpp b/src/tracks/sample_track.cpp index f018d70a93..48c88110a9 100644 --- a/src/tracks/sample_track.cpp +++ b/src/tracks/sample_track.cpp @@ -241,14 +241,13 @@ void FASTCALL sampleTCO::saveSettings( QDomDocument & _doc, QDomElement sampletco_de = _doc.createElement( nodeName() ); if( _parent.nodeName() == "clipboard" ) { - sampletco_de.setAttribute( "pos", QString::number( -1 ) ); + sampletco_de.setAttribute( "pos", -1 ); } else { - sampletco_de.setAttribute( "pos", QString::number( - startPosition() ) ); + sampletco_de.setAttribute( "pos", startPosition() ); } - sampletco_de.setAttribute( "len", QString::number( length() ) ); + sampletco_de.setAttribute( "len", length() ); sampletco_de.setAttribute( "src", sampleFile() ); if( sampleFile() == "" ) { diff --git a/src/widgets/fade_button.cpp b/src/widgets/fade_button.cpp new file mode 100644 index 0000000000..7f20b9894f --- /dev/null +++ b/src/widgets/fade_button.cpp @@ -0,0 +1,141 @@ +/* + * fade_button.cpp - implementation of fade-button + * + * Copyright (c) 2005 Tobias Doerffel + * + * 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 "fade_button.h" + +#ifdef QT4 + +#include +#include +#include + +#else + +#include +#include +#include + +#endif + + +fadeButton::fadeButton( const QColor & _normal_color, + const QColor & _activated_color, QWidget * _parent ) : + QButton( _parent ), + m_state( 0.0f ), + m_normalColor( _normal_color ), + m_activatedColor( _activated_color ) +{ +#ifndef QT4 + setBackgroundMode( NoBackground ); +#endif +} + + + + +fadeButton::~fadeButton() +{ +} + + + + +void fadeButton::activate( void ) +{ + if( m_state > 0.0f ) + { + m_state = 1.00f; + } + else + { + m_state = 1.1f; + nextState(); + } +} + + + +void fadeButton::reset( void ) +{ + m_state = 0.0f; + update(); +} + + + + + +void fadeButton::paintEvent( QPaintEvent * _pe ) +{ + QColor col = m_normalColor; + if( m_state > 0.0f ) + { + const int r = (int)( m_normalColor.red() * + ( 1.0f - m_state ) + + m_activatedColor.red() * m_state ); + const int g = (int)( m_normalColor.green() * + ( 1.0f - m_state ) + + m_activatedColor.green() * m_state ); + const int b = (int)( m_normalColor.blue() * + ( 1.0f - m_state ) + + m_activatedColor.blue() * m_state ); + col.setRgb( r, g, b ); + } +#ifdef QT4 + QPainter p( this ); +#else + QPixmap draw_pm( rect().size() ); + draw_pm.fill( col ); + + QPainter p( &draw_pm, this ); +#endif + p.setPen( QColor( 0, 0, 0 ) ); + p.drawRect( 0, 0, width(), height() ); +#ifndef QT4 + // and blit all the drawn stuff on the screen... + bitBlt( this, rect().topLeft(), &draw_pm ); +#endif +} + + + + +void fadeButton::nextState( void ) +{ + if( m_state > 0.0f ) + { + m_state -= 0.1f; + QTimer::singleShot( 20, this, SLOT( nextState( void ) ) ); + // we might be called out of another thread than the GUI-/ + // event-loop-thread, so let the timer update ourself + QTimer::singleShot( 0, this, SLOT( update( void ) ) ); + } +} + + + + +#include "fade_button.moc" + diff --git a/src/widgets/text_float.cpp b/src/widgets/text_float.cpp index d8543f4197..711ea0e188 100644 --- a/src/widgets/text_float.cpp +++ b/src/widgets/text_float.cpp @@ -158,6 +158,10 @@ textFloat * textFloat::displayMessage( const QString & _msg, int _timeout, } #else QWidget * mw = qApp->mainWidget(); + if( mw == NULL ) + { + mw = qApp->desktop(); + } #endif textFloat * tf = new textFloat( ( _parent == NULL ) ? mw : _parent ); if( _parent != NULL ) diff --git a/src/widgets/tool_button.cpp b/src/widgets/tool_button.cpp index fa34dab786..b78fb7db54 100644 --- a/src/widgets/tool_button.cpp +++ b/src/widgets/tool_button.cpp @@ -48,6 +48,8 @@ toolButton::toolButton( const QPixmap & _pixmap, const QString & _tooltip, setFixedSize( 30, 30 ); setIcon( _pixmap ); leaveEvent( NULL ); + connect( this, SIGNAL( toggled( bool ) ), this, + SLOT( toggledBool( bool ) ) ); } @@ -85,3 +87,18 @@ void toolButton::leaveEvent( QEvent * ) #endif } + + + +void toolButton::toggledBool( bool _on ) +{ + if( _on == TRUE ) + { + emit( clicked() ); + } +} + + + +#include "tool_button.moc" + diff --git a/src/widgets/visualization_widget.cpp b/src/widgets/visualization_widget.cpp index 910806ace6..e03632ffb3 100644 --- a/src/widgets/visualization_widget.cpp +++ b/src/widgets/visualization_widget.cpp @@ -56,30 +56,23 @@ visualizationWidget::visualizationWidget( const QPixmap & _bg, QWidget * _p, visualizationTypes _vtype ) : QWidget( _p ), s_background( _bg ), - m_enabled( FALSE ) + m_enabled( TRUE ) { #ifndef QT4 setBackgroundMode( Qt::NoBackground ); #endif + setFixedSize( s_background.width(), s_background.height() ); + const Uint32 frames = mixer::inst()->framesPerAudioBuffer(); m_buffer = bufferAllocator::alloc( frames ); mixer::inst()->clearAudioBuffer( m_buffer, frames ); -/* for( Uint32 frame = 0; frame < frames; ++frame ) - { - for( Uint8 chnl = 0; chnl < SURROUND_CHANNELS; ++chnl ) - { - m_buffer[frame][chnl] = 0.0f; - } - }*/ - - setFixedSize( s_background.width(), s_background.height() ); m_updateTimer = new QTimer( this ); connect( m_updateTimer, SIGNAL( timeout() ), this, SLOT( update() ) ); - if( m_enabled ) + if( m_enabled == TRUE ) { m_updateTimer->start( UPDATE_TIME ); } @@ -106,7 +99,7 @@ visualizationWidget::~visualizationWidget() void visualizationWidget::setAudioBuffer( const surroundSampleFrame * _ab, Uint32 _frames ) { - if( m_enabled ) + if( m_enabled == TRUE ) { memcpy( m_buffer, *_ab, _frames * BYTES_PER_SURROUND_FRAME); } @@ -121,13 +114,12 @@ void visualizationWidget::paintEvent( QPaintEvent * ) QPainter p( this ); #else QPixmap draw_pm( rect().size() ); - //draw_pm.fill( this, rect().topLeft() ); QPainter p( &draw_pm, this ); #endif p.drawPixmap( 0, 0, s_background ); - if( m_enabled ) + if( m_enabled == TRUE ) { float master_output = mixer::inst()->masterGain(); Uint16 w = width()-4; @@ -203,7 +195,7 @@ void visualizationWidget::mousePressEvent( QMouseEvent * _me ) if( _me->button() == Qt::LeftButton ) { m_enabled = !m_enabled; - if( m_enabled ) + if( m_enabled == TRUE ) { m_updateTimer->start( UPDATE_TIME ); }