diff --git a/ChangeLog b/ChangeLog index 80ffc5fbe..b0d22f67c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,98 @@ +2005-12-04 Tobias Doerffel + + * include/midi_alsa_raw.h: + * include/midi_client.h: + * include/midi_dummy.h: + * include/midi_oss.h: + * src/midi/midi_alsa_raw.cpp: + * src/midi/midi_client.cpp: + * src/midi/midi_oss.cpp: + renamed class midiRawClient to midiClientRaw + + * include/pattern.h: + * src/core/song_editor.cpp: + * src/tracks/pattern.cpp: + do not hang in endless loop when rendering pattern with enabled + looping-points + + * src/core/time_line.cpp: + align looping-points on bars + + * include/bb_editor.h: + * include/piano_roll.h: + * include/song_editor.h: + * include/timeline.h: + * include/tool_button.h: + * src/core/bb_editor.cpp: + * src/core/piano_roll.cpp: + * src/core/song_editor.cpp: + * src/core/timeline.cpp: + redesigned toolbars of song-editor, bb-editor and piano-roll - now + they're looking really cool and especially time-line-features are much + more usable + + * include/song_editor.cpp: + * src/core/lmms_main_win.cpp: + * src/core/song_editor.cpp: + - added main-toolbar at bottom of screen and moved several widgets from + song-editor-toolbar into it + - added high-quality-button for switching to 88200/96000 Hz + + * src/widgets/tab_widget.cpp: + reversed scroll-wheel-direction for changing tab + +2005-12-03 Tobias Doerffel + + * src/core/main.cpp: + - better handling of command-line options + - added help switch + - fixed bugs concerning rendering from command-line + + * include/audio_alsa.h: + * include/audio_device.h: + * include/audio_dummy.h: + * include/audio_file_device.h: + * include/audio_file_ogg.h: + * include/audio_file_wave.h + * include/audio_jack.h: + * include/audio_oss.h: + * include/audio_sdl.h: + * include/export.h: + * include/export_project_dialog.h: + * include/mixer.h: + * include/pattern.h + * include/song_editor.h: + * src/audio/audio_alsa.cpp: + * src/audio/audio_device.cpp: + * src/audio/audio_file_device.cpp: + * src/audio/audio_file_ogg.cpp: + * src/audio/audio_file_wave.cpp: + * src/audio/audio_jack.cpp: + * src/audio/audio_oss.cpp: + * src/audio/audio_port.cpp: + * src/audio/audio_sdl.cpp: + * src/core/export_project_dialog.cpp: + * src/core/lmms_main_win.cpp: + * src/core/main.cpp: + * src/core/mixer.cpp: + * src/core/song_editor.cpp: + * src/track/pattern.cpp: + changed architecture of mixer-system from push- to pull-architecture + which makes almost all things (song-export, pattern-freezing etc.) much + easier and also results in a better performance (especially when using + JACK) - additionally LMMS doesn't take 100% CPU anymore + +2005-12-02 Tobias Doerffel + + * src/core/config_mgr.cpp: + do not try to re-run wizard in case of version mismatches + + * configure.in: + * plugins/Makefile.am: + * presets/Makefile.am: + dropped ladspa_sine_1063-plugin as it is only for experimental + purposes + 2005-11-29 Tobias Doerffel * plugins/vestige/vestige.h: diff --git a/Makefile.am b/Makefile.am index e6a2023b5..1d7dc8a12 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,7 +48,6 @@ lmms_MOC = \ ./bb_track.moc \ ./channel_track.moc \ ./config_mgr.moc \ - ./crystal_button.moc \ ./envelope_and_lfo_widget.moc \ ./envelope_tab_widget.moc \ ./export_project_dialog.moc \ @@ -157,7 +156,6 @@ lmms_SOURCES = \ $(srcdir)/src/tracks/channel_track.cpp \ $(srcdir)/src/tracks/pattern.cpp \ $(srcdir)/src/tracks/sample_track.cpp \ - $(srcdir)/src/widgets/crystal_button.cpp \ $(srcdir)/src/widgets/group_box.cpp \ $(srcdir)/src/widgets/kmultitabbar.cpp \ $(srcdir)/src/widgets/knob.cpp \ @@ -212,7 +210,6 @@ lmms_SOURCES = \ $(srcdir)/include/envelope_and_lfo_widget.h \ $(srcdir)/include/about_dialog.h \ $(srcdir)/include/oscillator.h \ - $(srcdir)/include/crystal_button.h \ $(srcdir)/include/arp_and_chords_tab_widget.h \ $(srcdir)/include/export.h \ $(srcdir)/include/group_box.h \ @@ -274,6 +271,7 @@ lmms_SOURCES = \ $(srcdir)/include/midi_tab_widget.h \ $(srcdir)/include/audio_port.h \ $(srcdir)/include/qxembed.h \ + $(srcdir)/include/tool_button.h \ $(srcdir)/include/midi_alsa_seq.h diff --git a/README b/README index e9fd1c832..bb5d69fb2 100644 --- a/README +++ b/README @@ -1,10 +1,10 @@ Linux MultiMedia Studio 0.1.1 ============================== -Copyright (c) 2004-2005 by Tobias Doerffel and others +Copyright (c) 2004-2005 by Tobias Doerffel and others. -The whole program is free software; you can redistribute it and/or modify +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. @@ -26,9 +26,9 @@ What is LMMS?? LMMS aims to be a free alternative to popular (but commercial and closed- source) programs like FruityLoops, Cubase and Logic giving you the ability of producing music with your computer by creating/synthesizing sounds, arranging -samples, playing live with keyboard and much more... +samples, using effects, playing live with keyboard and much more... -LMMS combines the features of a tracker-/sequencer-program (pattern-/channel-/ +LMMS combines the features of a sequencer-program (pattern-/channel-/ sample-/song-/effect-management) and those of powerful synthesizers and samplers in a modern, user-friendly and easy to use graphical user-interface. @@ -47,23 +47,23 @@ least 500 MHz, but for really enjoying LMMS less than 1 GHz makes no sense... Required libraries are: -- multihreaded version of Qt 3.0 (3.2 recommended) or higher (tested up to - 4.0.0) with devel-files +- multithreaded version of Qt 3.0 (at least 3.2 recommended) or higher (tested + up to 4.0.0) with devel-files Optional, but strongly recommended: +- JACK with devel-files - libvorbis with devel-files - libalsa with devel-files - SDL_sound (tested with 0.1.5 & 1.0.1) with devel-files - SDL with devel-files - libsamplerate with devel-files - libsndfile with devel-files -- JACK with devel-files -- libfst + header-files from Steinberg SDK +- WINE, WINE-devel-files + header-files from Steinberg SDK For compiling you should have an up to date GCC with g++. -LMMS has been (successfully) tested under Debian Sarge 3.1, Fedora Core 2-4, -and SuSE Linux 9.0-9.3 with Qt 3.[23].x and Qt 4.0.0. -It was compiled using GCC 3.3.x, GCC 3.4.x and GCC 4.0.x. +LMMS has been (successfully) tested under Debian Sarge 3.1 / unstable, +Fedora Core 2-4, and SuSE Linux 9.0-9.3 with Qt 3.[23].x and Qt 4.0.0. +It was compiled using GCC 2.95, 3.3.x, GCC 3.4.x and GCC 4.0.x. If you have problems with compiling or running LMMS, find any bug or have suggestions and so on, please feel free to e-mail me (for mail-address see @@ -71,6 +71,20 @@ below)! +Building +-------- + +See INSTALL for information on how to build LMMS. + +Please also take a look at + +./configure --help + +There you'll see a lot of options which partly might be interesting for you. +For example if you want to build LMMS with VST-support, you have to run +configure with --with-vst switch. Otherwise LMMS support won't be built! + + Join LMMS-development ---------------------- diff --git a/TODO b/TODO index a4dacda1e..8b182ad42 100644 --- a/TODO +++ b/TODO @@ -1,23 +1,21 @@ +to be done as soon as possible: + +- add note-len- and note-alignment-selectbox to piano-roll +- make it possible in bb-editor to add single beats to beat-patterns +- MIDI/note-debug!! +- select connected midi-device in midi-setup-tabwidget - fix audio/midi-settings stuff/translation -- check ladspa-header - arpeggio: send midi-out-events via channel-track - tooltips for controls in MIDI-tab - sample-track: sane bg and wave-color -- complete toolbar-redesign in song-editor, bb-editor and piano-roll!!! - dnd everywhere: presets, samples (afp/sample-track), TCO's, knob-values - DSSI-support -- move VST-code into separate class which can use several backends (libfst, dssi-vst and vst-server) -> add libfst/dssi-vst/vstserver-check to configure.in - 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 -- pattern freeze -> do not endless loop if looping-points are enabled -- solve problem with knob-control-precision -- add note-len- and note-alignment-selectbox to piano-roll - only redraw region given by paint-event in pattern, bbTCO, sampleTCO etc. -- make LMMS an ALSA-sequencer-client - - use midi-maps - - process program-/channel-change-events from MIDI-files - - setup MIDI-channel and -program in MIDI-Out +- use midi-maps +- process program-/channel-change-events from MIDI-files - pre-listen when opening sample with QFileDialog - level-meters in output-graph and channel-track - panning-editing in piano-roll @@ -32,7 +30,7 @@ - rewrite export-project-dialog using layout-mechanism - dynamic pitch-change - make piano-roll use the global clipboard?? -- add languages: +- add more localizations: - Italian - Swedish - Norwegian @@ -41,14 +39,12 @@ -Things to be done anytime in the future +to be done somewhen in the future: - effect-board -> live-fx from input -- event-system +- event/automation-system - chord-editor? - WAVE/OGG/MP3-Import -> FFT-analysis -> write notes - FLP-Import - classical note-edit-window -> also ability of printing and maybe later scanning & recognition of notes - add FLAC as export-format? -- better commented source... -- optimize, optimize, optimize..... diff --git a/configure.in b/configure.in index b2931a6dd..592625f21 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-cvs20051129, tobydox/at/users.sourceforge.net) -AM_INIT_AUTOMAKE(lmms, 0.1.1-cvs20051129) +AC_INIT(lmms, 0.1.1-cvs20051204, tobydox/at/users.sourceforge.net) +AM_INIT_AUTOMAKE(lmms, 0.1.1-cvs20051204) AM_CONFIG_HEADER(config.h) @@ -62,8 +62,6 @@ AH_TEMPLATE(SDL_SDL_SOUND_H, [Define to location of SDL_sound.h]) OLD_LIBS="$LIBS" LIBS="$LIBS -lpthread" -AC_CHECK_FUNCS([pthread_getattr_np]) - # check for SDL-lib AC_ARG_WITH(sdl, AS_HELP_STRING([--without-sdl], @@ -158,10 +156,10 @@ fi AM_CONDITIONAL(HAVE_LIBJACK, test ! -z "$HAVE_JACK_JACK_H") -# check for proper wine-installation and existing steinberg headers +# check for proper wine-installation and existing Steinberg headers AC_ARG_WITH(vst, AS_HELP_STRING([--with-vst], - [enable support for VST-plugin-hosting]), [ with_vst=yes ], [ with_vst=no ]) + [enable support for builtin VST-plugin-hosting]), [ with_vst=yes ], [ with_vst=no ]) AH_TEMPLATE(HAVE_VST_AEFFECTX_H, [Define to 1 if you have the header file.]) if test "x$with_vst" = "xyes" ; then AC_CHECK_HEADER(vst/aeffectx.h, HAVE_VST_AEFFECTX_H="true") @@ -251,11 +249,11 @@ AM_CONDITIONAL(HAVE_LIBSF, test ! -z "$HAVE_SNDFILE_H") AC_ARG_WITH(nosmpdecs, AS_HELP_STRING([--without-sample-decoders], - [force compiling LMMS even if libraries for sample-decoding were found]), + [force compiling LMMS even if no usable libraries for sample-decoding were found]), [ with_smpdecs=yes ]) if test -z "$HAVE_SND_FILE" -a -z "$HAVE_SDL_SDL_SOUND_H" -a -z "$OGG_SUPPORT" -a ! -z "$with_smpdecs"; then - AC_MSG_ERROR([*** neither libsndfile nor SDL_sound nor libvorbis (or according devel-files) were found which would make LMMS unable to load any samples, so please install at least one of the packages and try again! Use --without-sample-decoders to force compiling LMMS.]) + AC_MSG_ERROR([*** neither libsndfile nor SDL_sound nor libvorbis (or according devel-files) were found which would make LMMS unable to load any samples so please install at least one of the packages and try again! Use --without-sample-decoders to force compiling without any sample-decoding-libraries.]) fi @@ -388,7 +386,6 @@ AC_CONFIG_FILES([Makefile presets/AudioFileProcessor/Makefile presets/MIDI-Out/Makefile presets/PluckedStringSynth/Makefile - presets/Sine1063Oscillator/Makefile presets/TripleOscillator/Makefile presets/VeSTige/Makefile projects/Makefile diff --git a/include/audio_alsa.h b/include/audio_alsa.h index e483de324..cfefff729 100644 --- a/include/audio_alsa.h +++ b/include/audio_alsa.h @@ -48,7 +48,7 @@ class lcdSpinBox; class QLineEdit; -class audioALSA : public audioDevice +class audioALSA : public audioDevice, public QThread { public: audioALSA( Uint32 _sample_rate, bool & _success_ful ); @@ -79,9 +79,9 @@ public: private: - virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, - Uint32 _frames, - float _master_gain ); + virtual void startProcessing( void ); + virtual void stopProcessing( void ); + virtual void run( void ); int FASTCALL setHWParams( Uint32 _sample_rate, Uint32 _channels, snd_pcm_access_t _access ); @@ -98,6 +98,7 @@ private: snd_pcm_sw_params_t * m_swParams; bool m_littleEndian; + volatile bool m_quit; } ; diff --git a/include/audio_device.h b/include/audio_device.h index fe2457fa6..4713a903e 100644 --- a/include/audio_device.h +++ b/include/audio_device.h @@ -32,11 +32,13 @@ #include #include +#include #else #include #include +#include #endif @@ -74,12 +76,6 @@ public: m_devMutex.unlock(); } - // called by mixer for writing final output-buffer with given sample- - // rate and master-gain - void FASTCALL writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, - Uint32 _src_sample_rate, - float _master_gain ); - // if audio-driver supports ports, classes inherting audioPort // (e.g. channel-tracks) can register themselves for making @@ -87,7 +83,7 @@ public: // them at a specific port - currently only supported by JACK virtual void registerPort( audioPort * _port ); virtual void unregisterPort( audioPort * _port ); - virtual void renamePort( audioPort * _port, const QString & _name ); + virtual void renamePort( audioPort * _port ); inline Uint32 sampleRate( void ) const @@ -100,6 +96,15 @@ public: return( m_channels ); } + void processNextBuffer( void ); + + virtual void startProcessing( void ) + { + } + + virtual void stopProcessing( void ) + { + } class setupWidget : public tabWidget @@ -122,10 +127,16 @@ public: protected: - // to be implemented by audio-driver - last step in a mixer period - virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, + // subclasses can overload this for being used in conjunction with + // processNextBuffer() + virtual void FASTCALL writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, - float _master_gain ) = 0; + float _master_gain ) + { + } + + // called by according driver for fetching new sound-data + Uint32 FASTCALL getNextBuffer( surroundSampleFrame * _ab ); // convert a given audio-buffer to a buffer in signed 16-bit samples // returns num of bytes in outbuf @@ -139,7 +150,8 @@ protected: Uint32 _frames ); // resample given buffer from samplerate _src_src to samplerate _dst_src - void FASTCALL resample( surroundSampleFrame * _src, Uint32 _frames, + void FASTCALL resample( const surroundSampleFrame * _src, + Uint32 _frames, surroundSampleFrame * _dst, Uint32 _src_sr, Uint32 _dst_sr ); @@ -159,6 +171,8 @@ private: SRC_STATE * m_srcState; #endif + surroundSampleFrame * m_buffer; + } ; diff --git a/include/audio_dummy.h b/include/audio_dummy.h index 349e8abf1..243894a51 100644 --- a/include/audio_dummy.h +++ b/include/audio_dummy.h @@ -68,13 +68,8 @@ public: private: - virtual void FASTCALL writeBufferToDev( surroundSampleFrame *, - Uint32 /*_frames*/, float ) - { - //usleep( (Uint32)( _frames * 1000.0f * 1000.0f / - // DEFAULT_SAMPLE_RATE ) ); - } - + // TODO: derive from QThread and call getNextBuffer() in an + // endless loop } ; diff --git a/include/audio_file_device.h b/include/audio_file_device.h index dd5c7683d..e38522f71 100644 --- a/include/audio_file_device.h +++ b/include/audio_file_device.h @@ -54,6 +54,7 @@ public: virtual ~audioFileDevice(); + protected: int FASTCALL writeData( const void * _data, int _len ); void seekToBegin( void ); diff --git a/include/audio_file_ogg.h b/include/audio_file_ogg.h index 43c551711..5aae4bf88 100644 --- a/include/audio_file_ogg.h +++ b/include/audio_file_ogg.h @@ -48,7 +48,7 @@ public: Uint16 _min_bitrate, Uint16 _max_bitrate ); ~audioFileOgg(); - static audioDevice * getInst( Uint32 _sample_rate, Uint32 _channels, + static audioFileDevice * getInst( Uint32 _sample_rate, Uint32 _channels, bool & _success_ful, const QString & _file, bool _use_vbr, @@ -63,7 +63,7 @@ public: private: - virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, + virtual void FASTCALL writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, float _master_gain ); diff --git a/include/audio_file_wave.h b/include/audio_file_wave.h index d05177736..4697fd801 100644 --- a/include/audio_file_wave.h +++ b/include/audio_file_wave.h @@ -41,7 +41,7 @@ public: Uint16 _min_bitrate, Uint16 _max_bitrate ); virtual ~audioFileWave(); - static audioDevice * getInst( Uint32 _sample_rate, Uint32 _channels, + static audioFileDevice * getInst( Uint32 _sample_rate, Uint32 _channels, bool & _success_ful, const QString & _file, bool _use_vbr, Uint16 _nom_bitrate, @@ -56,7 +56,7 @@ public: private: - virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, + virtual void FASTCALL writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, float _master_gain ); @@ -83,8 +83,6 @@ private: Uint32 data_bytes; // total size of sample-data } m_waveFileHeader; - //outputSampleType * m_outputBuffer; - } ; diff --git a/include/audio_jack.h b/include/audio_jack.h index b402d7bf2..a44c776aa 100644 --- a/include/audio_jack.h +++ b/include/audio_jack.h @@ -44,12 +44,14 @@ #include #include #include +#include #else #include #include #include +#include #endif @@ -90,34 +92,38 @@ public: private: - virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, - Uint32 _frames, - float _master_gain ); + virtual void startProcessing( void ); + virtual void stopProcessing( void ); virtual void registerPort( audioPort * _port ); virtual void unregisterPort( audioPort * _port ); - virtual void renamePort( audioPort * _port, const QString & _name ); + virtual void renamePort( audioPort * _port ); static int processCallback( jack_nframes_t _nframes, void * _udata ); - static int bufSizeCallback( jack_nframes_t _nframes, void * _udata ); static void shutdownCallback( void * _udata ); jack_client_t * m_client; + + bool m_stopped; + + QMutex m_processCallbackMutex; + vvector m_outputPorts; - struct bufset + surroundSampleFrame * m_outBuf; + + + Uint32 m_framesDoneInCurBuf; + Uint32 m_framesToDoInCurBuf; + + + struct stereoPort { - sampleType * buf; - Uint32 frames; + jack_port_t * ports[2]; } ; - vlist > m_bufferSets; - Uint32 m_framesDoneInCurBuf; - volatile Uint32 m_frameSync; - - Uint32 m_jackBufSize; - - QMutex m_bufMutex; + typedef QMap jackPortMap; + jackPortMap m_portMap; } ; diff --git a/include/audio_oss.h b/include/audio_oss.h index 76ffe4104..aa5414065 100644 --- a/include/audio_oss.h +++ b/include/audio_oss.h @@ -44,7 +44,7 @@ class lcdSpinBox; class QLineEdit; -class audioOSS : public audioDevice +class audioOSS : public audioDevice, public QThread { public: audioOSS( Uint32 _sample_rate, bool & _success_ful ); @@ -74,13 +74,14 @@ public: private: - virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, - Uint32 _frames, - float _master_gain ); + virtual void startProcessing( void ); + virtual void stopProcessing( void ); + virtual void run( void ); int m_audioFD; bool m_convertEndian; + volatile bool m_quit; } ; diff --git a/include/audio_port.h b/include/audio_port.h index 1a995ca3c..4bc83ae13 100644 --- a/include/audio_port.h +++ b/include/audio_port.h @@ -80,6 +80,11 @@ public: m_nextFxChannel = _chnl; } + const QString & name( void ) const + { + return( m_name ); + } + void setName( const QString & _new_name ); enum bufferUsages @@ -94,6 +99,8 @@ private: bool m_extOutputEnabled; fxChnl m_nextFxChannel; + QString m_name; + } ; diff --git a/include/audio_sample_recorder.h b/include/audio_sample_recorder.h index 809b83dff..014d0e18f 100644 --- a/include/audio_sample_recorder.h +++ b/include/audio_sample_recorder.h @@ -62,7 +62,7 @@ public: private: - virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, + virtual void FASTCALL writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, float _master_gain ); diff --git a/include/audio_sdl.h b/include/audio_sdl.h index f4654a6f3..8354e9c50 100644 --- a/include/audio_sdl.h +++ b/include/audio_sdl.h @@ -37,18 +37,6 @@ #endif -#include "qt3support.h" - -#ifdef QT4 - -#include - -#else - -#include - -#endif - #include SDL_SDL_H #include SDL_SDL_AUDIO_H @@ -87,20 +75,14 @@ public: private: - virtual void FASTCALL writeBufferToDev( surroundSampleFrame * _ab, - Uint32 _frames, - float _master_gain ); - - void clearBuffer( void ); + virtual void startProcessing( void ); + virtual void stopProcessing( void ); static void sdlAudioCallback( void * _udata, Uint8 * _buf, int _len ); SDL_AudioSpec m_audioHandle; - outputSampleType * m_buffer; - - QMutex m_bufMutex; - QMutex m_callbackMutex; + surroundSampleFrame * m_outBuf; bool m_convertEndian; diff --git a/include/bb_editor.h b/include/bb_editor.h index 89333c26b..13c28fe38 100644 --- a/include/bb_editor.h +++ b/include/bb_editor.h @@ -33,7 +33,7 @@ #include "lmms_main_win.h" -class pixmapButton; +class toolButton; class songEditor; class QPixmap; @@ -88,8 +88,6 @@ protected: virtual void keyPressEvent( QKeyEvent * _ke ); virtual void resizeEvent( QResizeEvent * _re ); - void updateBackground( void ); - protected slots: void play( void ); @@ -105,10 +103,11 @@ private: static bbEditor * s_instanceOfMe; - static QPixmap * s_titleArtwork; - pixmapButton * m_playButton; - pixmapButton * m_stopButton; + QWidget * m_toolBar; + + toolButton * m_playButton; + toolButton * m_stopButton; friend class songEditor; diff --git a/include/export.h b/include/export.h index 943b720e5..dc22b1bcc 100644 --- a/include/export.h +++ b/include/export.h @@ -27,10 +27,11 @@ #include "types.h" -class audioDevice; + +class audioFileDevice; -typedef audioDevice * ( * getDeviceInst)( Uint32 _sample_rate, +typedef audioFileDevice * ( * getDeviceInst)( Uint32 _sample_rate, Uint32 _channels, bool & _success_ful, const QString & _file, @@ -48,6 +49,7 @@ enum fileTypes } ; + struct fileEncodeDevice { fileTypes m_fileType; @@ -56,6 +58,7 @@ struct fileEncodeDevice getDeviceInst m_getDevInst; } ; + extern fileEncodeDevice fileEncodeDevices[]; diff --git a/include/export_project_dialog.h b/include/export_project_dialog.h index 5bb558662..bb86180a8 100644 --- a/include/export_project_dialog.h +++ b/include/export_project_dialog.h @@ -62,7 +62,6 @@ class exportProjectDialog : public QDialog public: exportProjectDialog( const QString & _file_name, QWidget * _parent ); ~exportProjectDialog(); - void FASTCALL updateProgressBar( int _new_val ); public slots: @@ -77,10 +76,16 @@ protected: private slots: void changedType( const QString & ); void cancelBtnClicked( void ); - void redrawProgressBar( void ); private: + void finishProjectExport( void ); + void abortProjectExport( void ); + + static fileTypes FASTCALL getFileTypeFromExtension( const QString & + _ext ); + static Sint16 s_availableBitrates[]; + QString m_fileName; QLabel * m_typeLbl; QComboBox * m_typeCombo; @@ -92,20 +97,9 @@ private: QPushButton * m_exportBtn; QPushButton * m_cancelBtn; QProgressBar * m_exportProgressBar; + fileTypes m_fileType; bool m_deleteFile; - int m_oldProgressVal; - int m_progressVal; - - QTimer * m_progressBarUpdateTimer; - - static Sint16 s_availableBitrates[]; - - void finishProjectExport( void ); - void abortProjectExport( void ); - - static fileTypes FASTCALL getFileTypeFromExtension( const QString & - _ext ); } ; diff --git a/include/midi_alsa_raw.h b/include/midi_alsa_raw.h index 3f0041808..37775bee2 100644 --- a/include/midi_alsa_raw.h +++ b/include/midi_alsa_raw.h @@ -58,7 +58,7 @@ struct pollfd; class QLineEdit; -class midiALSARaw : public midiRawClient, public QThread +class midiALSARaw : public midiClientRaw, public QThread { public: midiALSARaw( void ); @@ -74,7 +74,7 @@ public: } - class setupWidget : public midiRawClient::setupWidget + class setupWidget : public midiClientRaw::setupWidget { public: setupWidget( QWidget * _parent ); diff --git a/include/midi_client.h b/include/midi_client.h index 7c7b55962..f15859b25 100644 --- a/include/midi_client.h +++ b/include/midi_client.h @@ -102,15 +102,14 @@ protected: - const Uint8 RAW_MIDI_PARSE_BUF_SIZE = 16; -class midiRawClient : public midiClient +class midiClientRaw : public midiClient { public: - midiRawClient( void ); - ~midiRawClient(); + midiClientRaw( void ); + virtual ~midiClientRaw(); protected: diff --git a/include/midi_dummy.h b/include/midi_dummy.h index 5eb38e42c..01dac7d09 100644 --- a/include/midi_dummy.h +++ b/include/midi_dummy.h @@ -32,11 +32,11 @@ #include "tab_widget.h" -class midiDummy : public midiRawClient +class midiDummy : public midiClientRaw { public: midiDummy() : - midiRawClient() + midiClientRaw() { } ~midiDummy() @@ -53,7 +53,7 @@ public: { public: setupWidget( QWidget * _parent ) : - midiRawClient::setupWidget( midiDummy::name(), _parent ) + midiClientRaw::setupWidget( midiDummy::name(), _parent ) { } diff --git a/include/midi_oss.h b/include/midi_oss.h index 7b90441ae..ebbdde4e3 100644 --- a/include/midi_oss.h +++ b/include/midi_oss.h @@ -40,7 +40,7 @@ class QLineEdit; -class midiOSS : public midiRawClient, public QThread +class midiOSS : public midiClientRaw, public QThread { public: midiOSS( void ); @@ -55,7 +55,7 @@ public: } - class setupWidget : public midiRawClient::setupWidget + class setupWidget : public midiClientRaw::setupWidget { public: setupWidget( QWidget * _parent ); diff --git a/include/mixer.h b/include/mixer.h index 7273ed711..8c6c31238 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -34,14 +34,12 @@ #ifdef QT4 -#include #include #include #else #include -#include #include #include @@ -104,11 +102,7 @@ const octaves BASE_OCTAVE = OCTAVE_4; -class mixer : -#ifndef QT4 - public QObject, -#endif - public QThread +class mixer : public QObject { Q_OBJECT public: @@ -202,20 +196,20 @@ public: - inline int sampleRate( void ) + inline Uint32 sampleRate( void ) { return( SAMPLE_RATES[m_qualityLevel] ); } - inline float masterOutput( void ) const + inline float masterGain( void ) const { - return( m_masterOutput ); + return( m_masterGain ); } - inline void setMasterOutput( float _mo ) + inline void setMasterGain( float _mo ) { - m_masterOutput = _mo; + m_masterGain = _mo; } @@ -235,12 +229,12 @@ public: void pause( void ) { - m_safetySyncMutex.lock(); + m_mixMutex.lock(); } void play( void ) { - m_safetySyncMutex.unlock(); + m_mixMutex.unlock(); } @@ -259,6 +253,8 @@ public: } + const surroundSampleFrame * renderNextBuffer( void ); + public slots: void setHighQuality( bool _hq_on = FALSE ); @@ -275,7 +271,7 @@ private: mixer(); ~mixer(); - void quitThread( void ); + void stopProcessing( void ); // we don't allow to create mixer by using copy-ctor @@ -283,7 +279,6 @@ private: { } - virtual void run( void ); audioDevice * tryAudioDevices( void ); @@ -292,11 +287,6 @@ private: void processBuffer( surroundSampleFrame * _buf, fxChnl _fx_chnl ); -/* sampleFrame * m_silence; -#ifndef DISABLE_SURROUND - surroundSampleFrame * m_surroundSilence;// cool, silence in surround ;-) -#endif*/ - vvector m_audioPorts; @@ -305,16 +295,16 @@ private: surroundSampleFrame * m_curBuf; surroundSampleFrame * m_nextBuf; - bool m_discardCurBuf; +/* bool m_discardCurBuf;*/ playHandleVector m_playHandles; playHandleVector m_playHandlesToRemove; Uint8 m_qualityLevel; - volatile float m_masterOutput; + volatile float m_masterGain; - volatile bool m_quit; +/* volatile bool m_quit;*/ audioDevice * m_audioDev; @@ -326,8 +316,8 @@ private: QString m_midiClientName; - QMutex m_safetySyncMutex; - QMutex m_devMutex; + QMutex m_mixMutex; +/* QMutex m_devMutex;*/ friend class lmmsMainWin; diff --git a/include/nstate_button.h b/include/nstate_button.h index 809489c9e..7e2a60db5 100644 --- a/include/nstate_button.h +++ b/include/nstate_button.h @@ -34,14 +34,14 @@ #ifdef QT4 -#include +#include #include #include #include #else -#include +#include #include #include #include @@ -49,7 +49,7 @@ #endif -class nStateButton : public QWidget +class nStateButton : public QPushButton { Q_OBJECT public: @@ -73,11 +73,11 @@ public slots: signals: - void stateChanged( int _n ); + void changedState( int _n ); protected: - virtual void paintEvent( QPaintEvent * _pe ); +/* virtual void paintEvent( QPaintEvent * _pe );*/ virtual void mousePressEvent( QMouseEvent * _me ); diff --git a/include/pattern.h b/include/pattern.h index 046fb0652..130cb9248 100644 --- a/include/pattern.h +++ b/include/pattern.h @@ -53,12 +53,9 @@ class channelTrack; class sampleBuffer; -class audioSampleRecorder; -class QTimer; class QProgressBar; class QPushButton; class QPixmap; -class patternFreezeStatusDialog; @@ -72,7 +69,7 @@ class pattern : public trackContentObject public: enum patternTypes { - BEAT_PATTERN, MELODY_PATTERN/*, EVENT_PATTERN*/ + BEAT_PATTERN, MELODY_PATTERN/*, AUTOMATION_PATTERN*/ } ; pattern( channelTrack * _channel_track ); @@ -83,9 +80,13 @@ public: virtual midiTime length( void ) const; + note * FASTCALL addNote( const note & _new_note ); + void FASTCALL removeNote( const note * _note_to_del ); + note * FASTCALL rearrangeNote( const note * _note_to_proc ); + void clearNotes( void ); inline noteVector & notes( void ) @@ -98,32 +99,39 @@ public: return( m_patternType ); } void FASTCALL setType( patternTypes _new_pattern_type ); + + inline const QString & name( void ) const { return( m_name ); } + inline void setName( const QString & _name ) { m_name = _name; update(); } + + inline channelTrack * getChannelTrack( void ) { return( m_channelTrack ); } + // functions which are part of freezing-feature + inline bool freezing( void ) const + { + return( m_freezing ); + } + inline bool frozen( void ) const { return( m_frozenPattern != NULL ); } + void FASTCALL playFrozenData( sampleFrame * _ab, Uint32 _start_frame, Uint32 _frames ); - inline bool isFreezing( void ) const - { - return( m_freezeRecorder != NULL ); - } - void finishFreeze( void ); note * FASTCALL noteAt( int _note_num ); @@ -147,7 +155,6 @@ protected slots: void changeName( void ); void freeze( void ); void unfreeze( void ); - void updateFreezeStatusDialog( void ); void abortFreeze( void ); @@ -177,9 +184,9 @@ private: QMutex m_frozenPatternMutex; sampleBuffer * m_frozenPattern; - audioSampleRecorder * m_freezeRecorder; - patternFreezeStatusDialog * m_freezeStatusDialog; - QTimer * m_freezeStatusUpdateTimer; + bool m_freezing; + volatile bool m_freezeAborted; + } ; diff --git a/include/piano_roll.h b/include/piano_roll.h index 7cd63f6f9..dc1328489 100644 --- a/include/piano_roll.h +++ b/include/piano_roll.h @@ -50,10 +50,9 @@ class QPainter; class QPixmap; class QScrollBar; -class crystalButton; +class toolButton; class pattern; class notePlayHandle; -class pixmapButton; class timeLine; class lmmsMainWin; @@ -112,10 +111,10 @@ protected slots: void horScrolled( int _new_pos ); void verScrolled( int _new_pos ); - void drawButtonToggled( bool = FALSE ); - void eraseButtonToggled( bool = FALSE ); - void selectButtonToggled( bool = FALSE ); - void moveButtonToggled( bool = FALSE ); + void drawButtonToggled( void ); + void eraseButtonToggled( void ); + void selectButtonToggled( void ); + void moveButtonToggled( void ); void copySelectedNotes( void ); void cutSelectedNotes( void ); @@ -160,8 +159,6 @@ private: static QPixmap * s_whiteKeyBigPm; static QPixmap * s_whiteKeySmallPm; - static QPixmap * s_artwork1; - static QPixmap * s_artwork2; static QPixmap * s_blackKeyPm; static QPixmap * s_toolDraw; static QPixmap * s_toolErase; @@ -171,18 +168,20 @@ private: static pianoRollKeyTypes prKeyOrder[]; - pixmapButton * m_playButton; - pixmapButton * m_recordButton; - pixmapButton * m_stopButton; + QWidget * m_toolBar; - crystalButton * m_drawButton; - crystalButton * m_eraseButton; - crystalButton * m_selectButton; - crystalButton * m_moveButton; + toolButton * m_playButton; + toolButton * m_recordButton; + toolButton * m_stopButton; - crystalButton * m_cutButton; - crystalButton * m_copyButton; - crystalButton * m_pasteButton; + toolButton * m_drawButton; + toolButton * m_eraseButton; + toolButton * m_selectButton; + toolButton * m_moveButton; + + toolButton * m_cutButton; + toolButton * m_copyButton; + toolButton * m_pasteButton; QComboBox * m_zoomingComboBox; diff --git a/include/qt3support.h b/include/qt3support.h index de8898af7..f20ea5c5e 100644 --- a/include/qt3support.h +++ b/include/qt3support.h @@ -52,6 +52,14 @@ typedef int csize; #define vvector QVector #define vlist QList +#include + +inline QString baseName( const QString & _file ) +{ + return( QFileInfo( _file ).absolutePath() + "/" + + QFileInfo( _file ).completeBaseName() ); +} + #else @@ -73,7 +81,6 @@ typedef int csize; // QMenu/QPopupMenu #define addAction insertItem -//#define addSeparator insertSeparator // QFile/QIODevice @@ -115,15 +122,8 @@ typedef int csize; #define setTextVisible setPercentageVisible -// QFileInfo -//#define completeSuffix extension -//#define suffix() extension( FALSE ) - - // QComboBox #define addItem insertItem -//#define currentIndex currentItem -//#define setCurrentIndex setCurrentItem // QString @@ -148,7 +148,6 @@ typedef int csize; #define NoFilter DefaultFilter #define homePath homeDirPath #define rootPath rootDirPath -//#define absolutePath absPath // QToolButton @@ -178,6 +177,17 @@ typedef unsigned int csize; #endif +#include + + +inline QString baseName( const QString & _file ) +{ + return( QFileInfo( _file ).dirPath() + "/" + + QFileInfo( _file ).baseName( TRUE ) ); +} + + + #if QT_VERSION < 0x030100 #include diff --git a/include/song_editor.h b/include/song_editor.h index df62206cd..d4d3e3131 100644 --- a/include/song_editor.h +++ b/include/song_editor.h @@ -40,7 +40,6 @@ #endif -#include "lmms_main_win.h" #include "track_container.h" #include "types.h" @@ -48,20 +47,18 @@ class QComboBox; class QLabel; class QPixmap; -class QPushButton; class QScrollBar; class QSlider; -class QToolButton; -class exportProjectDialog; class lcdSpinBox; +class lmmsMainWin; class pattern; class projectNotes; class timeLine; +class toolButton; class visualizationWidget; - const int MIN_BPM = 10; const int DEFAULT_BPM = 140; const int MAX_BPM = 999; @@ -142,19 +139,20 @@ public: return( m_exporting == TRUE && m_playPos[PLAY_SONG].getTact() >= lengthInTacts() + 1 ); } - inline void setExportProjectDialog( exportProjectDialog * _epd ) - { - m_epd = _epd; - } + inline playModes playMode( void ) const { return( m_playMode ); } + inline playPos & getPlayPos( playModes _pm ) { return( m_playPos[_pm] ); } + tact lengthInTacts( void ) const; + + int getBPM( void ); // every function that replaces current file (e.g. creates new file, @@ -228,8 +226,8 @@ protected: protected slots: - void insertTact( void ); - void removeTact( void ); + void insertBar( void ); + void removeBar( void ); void addBBTrack( void ); void addSampleTrack( void ); void scrolled( int _new_pos ); @@ -243,7 +241,6 @@ protected slots: void masterPitchPressed( void ); void masterPitchMoved( int _new_val ); void masterPitchReleased( void ); - void toggleHQMode( void ); void updatePosition( const midiTime & _t ); @@ -264,7 +261,6 @@ private: } midiTime length( void ) const; - tact lengthInTacts( void ) const; inline tact64th currentTact64th( void ) const { return( m_playPos[m_playMode].getTact64th() ); @@ -278,8 +274,10 @@ private: QScrollBar * m_leftRightScroll; - QToolButton * m_playButton; - QToolButton * m_stopButton; + QWidget * m_toolBar; + + toolButton * m_playButton; + toolButton * m_stopButton; lcdSpinBox * m_bpmSpinBox; QSlider * m_masterVolumeSlider; @@ -288,11 +286,10 @@ private: visualizationWidget * m_masterOutputGraph; - QToolButton * m_addChannelTrackButton; - QToolButton * m_addBBTrackButton; - QToolButton * m_addSampleTrackButton; - QToolButton * m_insertTactButton; - QToolButton * m_removeTactButton; + toolButton * m_addBBTrackButton; + toolButton * m_addSampleTrackButton; + toolButton * m_insertBarButton; + toolButton * m_removeBarButton; QComboBox * m_zoomingComboBox; @@ -314,8 +311,6 @@ private: bool m_scrollBack; - exportProjectDialog * m_epd; - projectNotes * m_projectNotes; @@ -336,7 +331,7 @@ private: - friend lmmsMainWin::~lmmsMainWin(); + friend class lmmsMainWin; diff --git a/include/timeline.h b/include/timeline.h index 378ca0d49..d3d602eb6 100644 --- a/include/timeline.h +++ b/include/timeline.h @@ -50,6 +50,22 @@ class timeLine : public QWidget { Q_OBJECT public: + enum autoScrollStates + { + AUTOSCROLL_ENABLED, AUTOSCROLL_DISABLED + } ; + + enum loopPointStates + { + LOOP_POINTS_DISABLED, LOOP_POINTS_ENABLED + } ; + + enum behaviourAtStopStates + { + BACK_TO_ZERO, BACK_TO_START, KEEP_STOP_POSITION + } ; + + timeLine( int _xoff, int _yoff, float _ppt, songEditor::playPos & _pos, const midiTime & _begin, QWidget * _parent ); ~timeLine(); @@ -59,15 +75,16 @@ public: return( m_pos ); } - enum behaviourAtStopStates + behaviourAtStopStates behaviourAtStop( void ) const { - BACK_TO_ZERO, BACK_TO_START, KEEP_STOP_POSITION - } ; + return( m_behaviourAtStop ); + } + bool loopPointsEnabled( void ) const + { + return( m_loopPoints == LOOP_POINTS_ENABLED ); + } - behaviourAtStopStates behaviourAtStop( void ) const; - - bool loopPointsEnabled( void ) const; inline const midiTime & loopBegin( void ) const { return( ( m_loopPos[0] < m_loopPos[1] ) ? @@ -94,10 +111,14 @@ public: update(); } + void addToolButtons( QWidget * _tool_bar ); + public slots: void updatePosition( const midiTime & = 0 ); + void toggleAutoScroll( int _n ); void toggleLoopPoints( int _n ); + void toggleBehaviourAtStop( int _n ); protected: @@ -114,14 +135,14 @@ private: m_ppt / 64.0f ) ); } - static QPixmap * s_timeLinePixmap; static QPixmap * s_posMarkerPixmap; static QPixmap * s_loopPointPixmap; + static QPixmap * s_loopPointDisabledPixmap; - nStateButton * m_autoScroll; - nStateButton * m_loopPoints; - nStateButton * m_behaviourAtStop; + autoScrollStates m_autoScroll; + loopPointStates m_loopPoints; + behaviourAtStopStates m_behaviourAtStop; int m_xOffset; int m_posMarkerX; @@ -141,17 +162,6 @@ private: int m_moveXOff; - enum autoScrollStates - { - AUTOSCROLL_ENABLED, AUTOSCROLL_DISABLED - } ; - - enum loopPointStates - { - LOOP_POINTS_DISABLED, LOOP_POINTS_ENABLED - } ; - - signals: void positionChanged( const midiTime & _t ); diff --git a/include/tool_button.h b/include/tool_button.h new file mode 100644 index 000000000..30b3344b6 --- /dev/null +++ b/include/tool_button.h @@ -0,0 +1,69 @@ +/* + * tool_button.h - declaration of class toolButton + * + * 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 _TOOL_BUTTON_H +#define _TOOL_BUTTON_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "qt3support.h" + +#ifdef QT4 + +#include + +#else + +#include + +#endif + +#include "tooltip.h" + + +class toolButton : public QPushButton +{ +public: + toolButton( const QPixmap & _pixmap, const QString & _tooltip, + QObject * _receiver, const char * _slot, + QWidget * _parent ) : + QPushButton( _parent ) + { + connect( this, SIGNAL( clicked() ), _receiver, _slot ); + toolTip::add( this, _tooltip ); + setPaletteBackgroundColor( QColor( 224, 224, 224 ) ); + setFixedSize( 30, 30 ); + setPixmap( _pixmap ); + } + + ~toolButton() + { + } + +} ; + +#endif diff --git a/plugins/Makefile.am b/plugins/Makefile.am index e1ce8b526..e689b77d3 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -2,6 +2,6 @@ if VST_SUPPORT VESTIGE_SUBDIR=vestige endif -SUBDIRS = audio_file_processor ladspa_sine_1063 midi_out plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR) +SUBDIRS = audio_file_processor midi_out plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR) diff --git a/resources/add_bb_track.png b/resources/add_bb_track.png index bed9f4a46..5097f0422 100644 Binary files a/resources/add_bb_track.png and b/resources/add_bb_track.png differ diff --git a/resources/add_sample_track.png b/resources/add_sample_track.png index 5f00cdd0e..5b27a2725 100644 Binary files a/resources/add_sample_track.png and b/resources/add_sample_track.png differ diff --git a/resources/autoscroll_off.png b/resources/autoscroll_off.png index 3fec30490..517886512 100644 Binary files a/resources/autoscroll_off.png and b/resources/autoscroll_off.png differ diff --git a/resources/autoscroll_on.png b/resources/autoscroll_on.png index b1355c686..4da52a470 100644 Binary files a/resources/autoscroll_on.png and b/resources/autoscroll_on.png differ diff --git a/resources/back_to_start.png b/resources/back_to_start.png index 2dc113ee2..a03742115 100644 Binary files a/resources/back_to_start.png and b/resources/back_to_start.png differ diff --git a/resources/back_to_zero.png b/resources/back_to_zero.png index 162ee36b4..28cbbd74c 100644 Binary files a/resources/back_to_zero.png and b/resources/back_to_zero.png differ diff --git a/resources/drum.png b/resources/drum.png new file mode 100644 index 000000000..43991cb27 Binary files /dev/null and b/resources/drum.png differ diff --git a/resources/hq_mode.png b/resources/hq_mode.png new file mode 100644 index 000000000..c8d74b106 Binary files /dev/null and b/resources/hq_mode.png differ diff --git a/resources/keep_stop_position.png b/resources/keep_stop_position.png index b13e6f10b..71d68aef8 100644 Binary files a/resources/keep_stop_position.png and b/resources/keep_stop_position.png differ diff --git a/resources/loop_point.png b/resources/loop_point.png index 0592ef9fb..2a5e586b8 100644 Binary files a/resources/loop_point.png and b/resources/loop_point.png differ diff --git a/resources/loop_point_disabled.png b/resources/loop_point_disabled.png new file mode 100644 index 000000000..cd0efae22 Binary files /dev/null and b/resources/loop_point_disabled.png differ diff --git a/resources/loop_points_off.png b/resources/loop_points_off.png index f0c10eb9a..941989df2 100644 Binary files a/resources/loop_points_off.png and b/resources/loop_points_off.png differ diff --git a/resources/loop_points_on.png b/resources/loop_points_on.png index d9a9e341d..a1a0f7f13 100644 Binary files a/resources/loop_points_on.png and b/resources/loop_points_on.png differ diff --git a/resources/pause.png b/resources/pause.png index 85f06664c..df8b2c150 100644 Binary files a/resources/pause.png and b/resources/pause.png differ diff --git a/resources/play.png b/resources/play.png index d43c2478a..5b33768c8 100644 Binary files a/resources/play.png and b/resources/play.png differ diff --git a/resources/record.png b/resources/record.png index 367a6dad2..479107305 100644 Binary files a/resources/record.png and b/resources/record.png differ diff --git a/resources/stop.png b/resources/stop.png index 9b35d2278..9d2d8d1e8 100644 Binary files a/resources/stop.png and b/resources/stop.png differ diff --git a/resources/timeline.png b/resources/timeline.png index db4ec891c..6093f28d6 100644 Binary files a/resources/timeline.png and b/resources/timeline.png differ diff --git a/resources/toolbar_bg.png b/resources/toolbar_bg.png index c8e8972d1..25ec99d72 100644 Binary files a/resources/toolbar_bg.png and b/resources/toolbar_bg.png differ diff --git a/src/audio/audio_alsa.cpp b/src/audio/audio_alsa.cpp index b3c7ed13d..6a78c218b 100644 --- a/src/audio/audio_alsa.cpp +++ b/src/audio/audio_alsa.cpp @@ -61,7 +61,8 @@ audioALSA::audioALSA( Uint32 _sample_rate, bool & _success_ful ) : m_handle( NULL ), m_hwParams( NULL ), m_swParams( NULL ), - m_littleEndian( isLittleEndian() ) + m_littleEndian( isLittleEndian() ), + m_quit( FALSE ) { _success_ful = FALSE; @@ -105,6 +106,7 @@ audioALSA::audioALSA( Uint32 _sample_rate, bool & _success_ful ) : audioALSA::~audioALSA() { + stopProcessing(); if( m_handle != NULL ) { snd_pcm_close( m_handle ); @@ -175,40 +177,77 @@ int audioALSA::handleError( int _err ) -void audioALSA::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_gain ) +void audioALSA::startProcessing( void ) { - outputSampleType * outbuf = bufferAllocator::alloc( - _frames * channels() ); - bufferAllocator::autoCleaner<> ac( outbuf ); + if( !running() ) + { + start(); + } +} - convertToS16( _ab, _frames, _master_gain, outbuf, + + + +void audioALSA::stopProcessing( void ) +{ + if( running() ) + { + m_quit = TRUE; + wait( 500 ); + terminate(); + } +} + + + + +void audioALSA::run( void ) +{ + surroundSampleFrame * temp = + bufferAllocator::alloc( + mixer::inst()->framesPerAudioBuffer() ); + outputSampleType * outbuf = + bufferAllocator::alloc( + mixer::inst()->framesPerAudioBuffer() * + channels() ); + m_quit = FALSE; + + while( m_quit == FALSE ) + { + const Uint32 frames = getNextBuffer( temp ); + + convertToS16( temp, frames, mixer::inst()->masterGain(), outbuf, m_littleEndian != isLittleEndian() ); - Uint32 frame = 0; + Uint32 frame = 0; + outputSampleType * ptr = outbuf; - while( frame < _frames ) - { - int err = snd_pcm_writei( m_handle, outbuf, _frames ); - - if( err == -EAGAIN ) + while( frame < frames ) { - continue; - } + int err = snd_pcm_writei( m_handle, ptr, frames ); - if( err < 0 ) - { - if( handleError( err ) < 0 ) + if( err == -EAGAIN ) { - printf( "Write error: %s\n", - snd_strerror( err ) ); - return; + usleep( 10 ); + continue; } - break; // skip this buffer + + if( err < 0 ) + { + if( handleError( err ) < 0 ) + { + printf( "Write error: %s\n", + snd_strerror( err ) ); + } + break; // skip this buffer + } + ptr += err * channels(); + frame += err; } - outbuf += err * channels(); - frame += err; } + + bufferAllocator::free( temp ); + bufferAllocator::free( outbuf ); } diff --git a/src/audio/audio_device.cpp b/src/audio/audio_device.cpp index 680c64628..05c2c0b9f 100644 --- a/src/audio/audio_device.cpp +++ b/src/audio/audio_device.cpp @@ -38,7 +38,9 @@ audioDevice::audioDevice( Uint32 _sample_rate, Uint8 _channels ) : m_sampleRate( _sample_rate ), - m_channels( _channels ) + m_channels( _channels ), + m_buffer( bufferAllocator::alloc( + mixer::inst()->framesPerAudioBuffer() ) ) { #ifdef HAVE_SAMPLERATE_H int error; @@ -64,34 +66,46 @@ audioDevice::~audioDevice() #ifdef HAVE_SAMPLERATE_H src_delete( m_srcState ); #endif + bufferAllocator::free( m_buffer ); unlock(); } -void audioDevice::writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, - Uint32 _src_sample_rate, float _master_gain ) +void audioDevice::processNextBuffer( void ) { + const Uint32 frames = getNextBuffer( m_buffer ); + writeBuffer( m_buffer, frames, mixer::inst()->masterGain() ); +} + + + + +Uint32 audioDevice::getNextBuffer( surroundSampleFrame * _ab ) +{ + Uint32 frames = mixer::inst()->framesPerAudioBuffer(); + const surroundSampleFrame * b = mixer::inst()->renderNextBuffer(); + // make sure, no other thread is accessing device lock(); - // now were save to access the device - if( _src_sample_rate != m_sampleRate ) + + // now were safe to access the device + if( mixer::inst()->sampleRate() != m_sampleRate ) { - surroundSampleFrame * temp = - bufferAllocator::alloc( - _frames * channels() ); - resample( _ab, _frames, temp, _src_sample_rate, m_sampleRate ); - writeBufferToDev( temp, _frames * m_sampleRate / - _src_sample_rate, _master_gain ); - bufferAllocator::free( temp ); + resample( b, frames, _ab, mixer::inst()->sampleRate(), + m_sampleRate ); + frames = frames * m_sampleRate / mixer::inst()->sampleRate(); } else { - writeBufferToDev( _ab, _frames, _master_gain ); + memcpy( _ab, b, frames * sizeof( surroundSampleFrame ) ); } + // release lock unlock(); + + return( frames ); } @@ -111,7 +125,7 @@ void audioDevice::unregisterPort( audioPort * _port ) -void audioDevice::renamePort( audioPort *, const QString & ) +void audioDevice::renamePort( audioPort * ) { } @@ -150,7 +164,8 @@ const float LP_FILTER_COEFFS[LP_FILTER_TAPS] = #endif -void FASTCALL audioDevice::resample( surroundSampleFrame * _src, Uint32 _frames, +void FASTCALL audioDevice::resample( const surroundSampleFrame * _src, + Uint32 _frames, surroundSampleFrame * _dst, Uint32 _src_sr, Uint32 _dst_sr ) { @@ -161,7 +176,7 @@ void FASTCALL audioDevice::resample( surroundSampleFrame * _src, Uint32 _frames, } m_srcData.input_frames = _frames; m_srcData.output_frames = _frames; - m_srcData.data_in = _src[0]; + m_srcData.data_in = (float *) _src[0]; m_srcData.data_out = _dst[0]; m_srcData.src_ratio = (float) _dst_sr / _src_sr; @@ -172,7 +187,7 @@ void FASTCALL audioDevice::resample( surroundSampleFrame * _src, Uint32 _frames, src_strerror( error ) ); } #else - if( _src_sr == 2*SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] ) + if( _src_sr == 2 * SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] ) { // we use a simple N-tap FIR-Filter with // precalculated/-designed LP-Coeffs diff --git a/src/audio/audio_file_device.cpp b/src/audio/audio_file_device.cpp index f7b822f43..0994e0a27 100644 --- a/src/audio/audio_file_device.cpp +++ b/src/audio/audio_file_device.cpp @@ -39,6 +39,7 @@ #include "audio_file_device.h" #include "export_project_dialog.h" +#include "buffer_allocator.h" audioFileDevice::audioFileDevice( Uint32 _sample_rate, Uint8 _channels, diff --git a/src/audio/audio_file_ogg.cpp b/src/audio/audio_file_ogg.cpp index 0b04f2b87..c243bea83 100644 --- a/src/audio/audio_file_ogg.cpp +++ b/src/audio/audio_file_ogg.cpp @@ -1,5 +1,5 @@ /* - * audio_file_ogg.cpp - Audio-device which encodes wave-stream and writes it + * audio_file_ogg.cpp - audio-device which encodes wave-stream and writes it * into an OGG-file. This is used for song-export. * * This file is based on encode.c from vorbis-tools-source, for more information @@ -27,17 +27,6 @@ */ -/* OggEnc - ** - ** This program is distributed under the GNU General Public License, version 2. - ** A copy of this license is included with this source. - ** - ** Copyright 2000-2002, Michael Smith - ** - ** Portions from Vorbize, (c) Kenneth Arnold - ** and libvorbis examples, (c) Monty - **/ - #include @@ -84,7 +73,7 @@ inline int audioFileOgg::writePage( void ) bool audioFileOgg::startEncoding( void ) { vorbis_comment vc; - char * comments = "Cool=This song was written with Linux " + char * comments = "Cool=This song has been made using Linux " "MultiMedia Studio"; int comment_length = strlen( comments ); @@ -185,7 +174,7 @@ bool audioFileOgg::startEncoding( void ) -void FASTCALL audioFileOgg::writeBufferToDev( surroundSampleFrame * _ab, +void FASTCALL audioFileOgg::writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, float _master_gain ) { @@ -253,7 +242,7 @@ void FASTCALL audioFileOgg::writeBufferToDev( surroundSampleFrame * _ab, void audioFileOgg::finishEncoding( void ) { // just for flushing buffers... - writeBufferToDev( NULL, 0, 0.0f ); + writeBuffer( NULL, 0, 0.0f ); // clean up ogg_stream_clear( &m_os ); diff --git a/src/audio/audio_file_wave.cpp b/src/audio/audio_file_wave.cpp index 3b03d94d3..323d5eb3e 100644 --- a/src/audio/audio_file_wave.cpp +++ b/src/audio/audio_file_wave.cpp @@ -1,5 +1,5 @@ /* - * audio_file_wave.cpp - Audio-device which encodes wave-stream and writes it + * audio_file_wave.cpp - audio-device which encodes wave-stream and writes it * into a WAVE-file. This is used for song-export. * * Copyright (c) 2004-2005 Tobias Doerffel @@ -87,7 +87,7 @@ bool audioFileWave::startEncoding( void ) -void FASTCALL audioFileWave::writeBufferToDev( surroundSampleFrame * _ab, +void FASTCALL audioFileWave::writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, float _master_gain ) { diff --git a/src/audio/audio_jack.cpp b/src/audio/audio_jack.cpp index 782e2c4c8..b1fafb8e7 100644 --- a/src/audio/audio_jack.cpp +++ b/src/audio/audio_jack.cpp @@ -28,12 +28,6 @@ #ifdef JACK_SUPPORT -#ifdef HAVE_UNISTD_H -// for usleep -#include -#endif - - #ifdef QT4 #include @@ -55,6 +49,7 @@ #include "buffer_allocator.h" #include "config_mgr.h" #include "lcd_spinbox.h" +#include "audio_port.h" @@ -62,10 +57,13 @@ audioJACK::audioJACK( Uint32 _sample_rate, bool & _success_ful ) : audioDevice( _sample_rate, tLimit( configManager::inst()->value( "audiojack", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ) ), + m_client( NULL ), + m_stopped( FALSE ), + m_processCallbackMutex(), + m_outBuf( bufferAllocator::alloc( + mixer::inst()->framesPerAudioBuffer() ) ), m_framesDoneInCurBuf( 0 ), - m_frameSync( 0 ), - m_jackBufSize( 0 ), - m_bufMutex() + m_framesToDoInCurBuf( 0 ) { _success_ful = FALSE; @@ -120,12 +118,6 @@ audioJACK::audioJACK( Uint32 _sample_rate, bool & _success_ful ) : // set process-callback jack_set_process_callback( m_client, processCallback, this ); - m_jackBufSize = jack_get_buffer_size( m_client ); - - // we need to know about buffer-size changes to know how long to block - // in writeToDev()-method - jack_set_buffer_size_callback( m_client, bufSizeCallback, this ); - // set shutdown-callback jack_on_shutdown( m_client, shutdownCallback, this ); @@ -140,7 +132,7 @@ audioJACK::audioJACK( Uint32 _sample_rate, bool & _success_ful ) : for( Uint8 ch = 0; ch < channels(); ++ch ) { - QString name = QString( "master_out_" ) + + QString name = QString( "master out " ) + ( ( ch % 2 ) ? "R" : "L" ) + QString::number( ch / 2 + 1 ); m_outputPorts.push_back( jack_port_register( m_client, @@ -212,80 +204,62 @@ audioJACK::audioJACK( Uint32 _sample_rate, bool & _success_ful ) : audioJACK::~audioJACK() { + while( m_portMap.size() ) + { + unregisterPort( m_portMap.begin().key() ); + } + if( m_client != NULL ) { jack_deactivate( m_client ); jack_client_close( m_client ); } - while( m_bufferSets.size() ) - { - while( m_bufferSets.front().size() ) - { - bufferAllocator::free( - m_bufferSets.front().front().buf ); - m_bufferSets.front().erase( - m_bufferSets.front().begin() ); - } - m_bufferSets.erase( m_bufferSets.begin() ); - } + bufferAllocator::free( m_outBuf ); + } -void audioJACK::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_gain ) +void audioJACK::startProcessing( void ) { - if( m_client == NULL ) - { - return; - } - - m_bufMutex.lock(); - - jack_transport_state_t ts = jack_transport_query( m_client, NULL ); - if( ts == JackTransportRolling ) - { - vvector bufs; - for( Uint8 chnl = 0; chnl < channels(); ++chnl ) - { - sampleType * buf = bufferAllocator::alloc( - _frames ); - for( Uint32 frame = 0; frame < _frames; ++frame ) - { - buf[frame] = _ab[frame][chnl] * _master_gain; - } - bufset b = { buf, _frames } ; - bufs.push_back( b ); - } - m_bufferSets.push_back( bufs ); - } - - m_frameSync += _frames; - - m_bufMutex.unlock(); - - // now wait until data has been collected/skipped by processCallback() - while( m_frameSync > m_jackBufSize ) - { -#ifdef HAVE_UNISTD_H -#ifdef HAVE_USLEEP - // just wait and give cpu-time to other processes - // tobydox 20051019: causes LMMS to hang up when locking - // several other mutexes, so skip it - //usleep( 200 ); - -#endif -#endif - } + m_stopped = FALSE; } -void audioJACK::registerPort( audioPort * ) +void audioJACK::stopProcessing( void ) { + m_stopped = TRUE; +} + + + + +void audioJACK::registerPort( audioPort * _port ) +{ + return; +/* // make sure, port is not already registered + unregisterPort( _port ); + const QString name[2] = { _port->name() + " L", + _port->name() + " R" } ; + + m_processCallbackMutex.lock(); + for( Uint8 ch = 0; ch < DEFAULT_CHANNELS; ++ch ) + { + m_portMap[_port].ports[ch] = jack_port_register( m_client, + name[ch]. +#ifdef QT4 + toAscii().constData(), +#else + ascii(), +#endif + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0 ); + } + m_processCallbackMutex.unlock();*/ } @@ -293,13 +267,45 @@ void audioJACK::registerPort( audioPort * ) void audioJACK::unregisterPort( audioPort * _port ) { + return; +/* if( m_portMap.contains( _port ) ) + { + m_processCallbackMutex.lock(); + for( Uint8 ch = 0; ch < DEFAULT_CHANNELS; ++ch ) + { + if( m_portMap[_port].ports[ch] != NULL ) + { + jack_port_unregister( m_client, + m_portMap[_port].ports[ch] ); + } + } + m_portMap.erase( m_portMap.find( _port ) ); + m_processCallbackMutex.unlock(); + }*/ } -void audioJACK::renamePort( audioPort *, const QString & ) +void audioJACK::renamePort( audioPort * _port ) { + return; +/* if( m_portMap.contains( _port ) ) + { + const QString name[2] = { _port->name() + " L", + _port->name() + " R" }; + for( Uint8 ch = 0; ch < DEFAULT_CHANNELS; ++ch ) + { + jack_port_set_name( m_portMap[_port].ports[ch], + name[ch]. +#ifdef QT4 + toAscii().constData() +#else + ascii() +#endif + ) ; + } + }*/ } @@ -308,6 +314,7 @@ void audioJACK::renamePort( audioPort *, const QString & ) int audioJACK::processCallback( jack_nframes_t _nframes, void * _udata ) { audioJACK * _this = static_cast( _udata ); + _this->m_processCallbackMutex.lock(); /* printf( "%f\n", jack_cpu_load( _this->m_client ) );*/ @@ -316,104 +323,78 @@ int audioJACK::processCallback( jack_nframes_t _nframes, void * _udata ) #endif jack_transport_state_t ts = jack_transport_query( _this->m_client, NULL ); - _this->m_bufMutex.lock(); - - if( ts != JackTransportRolling ) - { - // always decrease frame-sync-var as we would do it if running - // in normal mode, so that the mixer-thread knows when to - // proceed - if( _nframes < _this->m_frameSync ) - { - _this->m_frameSync -= _nframes; - } - else - { - _this->m_frameSync = 0; - } - _this->m_bufMutex.unlock(); - return( 0 ); - } vvector outbufs( _this->channels(), NULL ); - Uint8 ch = 0; + Uint8 chnl = 0; for( vvector::iterator it = - outbufs.begin(); it != outbufs.end(); ++it, ++ch ) + outbufs.begin(); it != outbufs.end(); ++it, ++chnl ) { *it = (jack_default_audio_sample_t *) jack_port_get_buffer( - _this->m_outputPorts[ch], _nframes ); + _this->m_outputPorts[chnl], _nframes ); } +/* const Uint32 frames = tMin( _nframes, + mixer::inst()->framesPerAudioBuffer() ); + for( jackPortMap::iterator it = _this->m_portMap.begin(); + it != _this->m_portMap.end(); ++it ) + { + for( Uint8 ch = 0; ch < DEFAULT_CHANNELS; ++ch ) + { + if( it.data().ports[ch] == NULL ) + { + continue; + } + jack_default_audio_sample_t * buf = + (jack_default_audio_sample_t *) jack_port_get_buffer( + it.data().ports[ch], + _nframes ); + for( Uint32 frame = 0; frame < frames; ++frame ) + { + buf[frame] = it.key()->firstBuffer()[ch][frame]; + } + } + }*/ jack_nframes_t done = 0; - while( done < _nframes ) + while( done < _nframes && _this->m_stopped == FALSE ) { - if( _this->m_bufferSets.size() == 0 ) - { - break; - } - jack_nframes_t todo = tMin( _nframes - done, - _this->m_bufferSets.front()[0].frames - + jack_nframes_t todo = tMin( + _nframes, + _this->m_framesToDoInCurBuf - _this->m_framesDoneInCurBuf ); - for( Uint8 ch = 0; ch < _this->channels(); ++ch ) + if( ts == JackTransportRolling ) { - memcpy( outbufs[ch] + done, - _this->m_bufferSets.front()[ch].buf + - _this->m_framesDoneInCurBuf, - sizeof( jack_default_audio_sample_t ) * - todo ); - } - _this->m_framesDoneInCurBuf += todo; - if( _this->m_framesDoneInCurBuf >= - _this->m_bufferSets.front()[0].frames ) - { - for( Uint8 ch = 0; ch < _this->channels(); ++ch ) + for( Uint8 chnl = 0; chnl < _this->channels(); ++chnl ) { - bufferAllocator::free( - _this->m_bufferSets.front()[ch].buf ); + for( Uint32 frame = 0; frame < todo; ++frame ) + { + outbufs[chnl][done+frame] = + _this->m_outBuf[_this->m_framesDoneInCurBuf+frame][chnl] * + mixer::inst()->masterGain(); + } } - _this->m_bufferSets.erase( - _this->m_bufferSets.begin() ); - _this->m_framesDoneInCurBuf = 0; } done += todo; - _this->m_frameSync -= todo; + _this->m_framesDoneInCurBuf += todo; + if( _this->m_framesDoneInCurBuf == _this->m_framesToDoInCurBuf ) + { + _this->m_framesToDoInCurBuf = _this->getNextBuffer( + _this->m_outBuf ); + _this->m_framesDoneInCurBuf = 0; + } } - // we have to clear the part of the buffers, if we could not fill - // because no usable data is left, otherwise there's baaaaaad - // noise... ;-) - if( done < _nframes ) + if( ts != JackTransportRolling || _this->m_stopped == TRUE ) { for( Uint8 ch = 0; ch < _this->channels(); ++ch ) { jack_default_audio_sample_t * b = outbufs[ch]; - memset( b + done, 0, - sizeof( *b ) * ( _nframes - done ) ); -/* for( Uint32 frame = done; frame < _nframes; ++frame ) - { - b[frame] = 0.0f; - }*/ + memset( b, 0, sizeof( *b ) * _nframes ); } } - _this->m_bufMutex.unlock(); - - return( 0 ); -} - - - - -int audioJACK::bufSizeCallback( jack_nframes_t _nframes, void * _udata ) -{ - audioJACK * _this = static_cast( _udata ); - -#ifdef LMMS_DEBUG - assert( _this != NULL ); -#endif - _this->m_jackBufSize = _nframes; + _this->m_processCallbackMutex.unlock(); return( 0 ); } diff --git a/src/audio/audio_oss.cpp b/src/audio/audio_oss.cpp index 0e08b4c54..f86a5b31e 100644 --- a/src/audio/audio_oss.cpp +++ b/src/audio/audio_oss.cpp @@ -95,7 +95,8 @@ audioOSS::audioOSS( Uint32 _sample_rate, bool & _success_ful ) : audioDevice( _sample_rate, tLimit( configManager::inst()->value( "audiooss", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ) ), - m_convertEndian( FALSE ) + m_convertEndian( FALSE ), + m_quit( FALSE ) { _success_ful = FALSE; @@ -231,6 +232,7 @@ audioOSS::audioOSS( Uint32 _sample_rate, bool & _success_ful ) : audioOSS::~audioOSS() { + stopProcessing(); close( m_audioFD ); } @@ -278,15 +280,52 @@ QString audioOSS::probeDevice( void ) -void audioOSS::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_gain ) +void audioOSS::startProcessing( void ) { - outputSampleType * outbuf = bufferAllocator::alloc( - _frames * channels() ); - int bytes = convertToS16( _ab, _frames, _master_gain, outbuf, - m_convertEndian ); - write( m_audioFD, outbuf, bytes ); + if( !running() ) + { + start(); + } +} + + + +void audioOSS::stopProcessing( void ) +{ + if( running() ) + { + m_quit = TRUE; + wait( 500 ); + terminate(); + } +} + + + + +void audioOSS::run( void ) +{ + surroundSampleFrame * temp = + bufferAllocator::alloc( + mixer::inst()->framesPerAudioBuffer() ); + outputSampleType * outbuf = + bufferAllocator::alloc( + mixer::inst()->framesPerAudioBuffer() * + channels() ); + m_quit = FALSE; + + while( m_quit == FALSE ) + { + const Uint32 frames = getNextBuffer( temp ); + + int bytes = convertToS16( temp, frames, + mixer::inst()->masterGain(), outbuf, + m_convertEndian ); + write( m_audioFD, outbuf, bytes ); + } + + bufferAllocator::free( temp ); bufferAllocator::free( outbuf ); } diff --git a/src/audio/audio_port.cpp b/src/audio/audio_port.cpp index 6329ae616..da752ed65 100644 --- a/src/audio/audio_port.cpp +++ b/src/audio/audio_port.cpp @@ -35,13 +35,15 @@ audioPort::audioPort( const QString & _name ) : m_secondBuffer( bufferAllocator::alloc( mixer::inst()->framesPerAudioBuffer() ) ), m_extOutputEnabled( FALSE ), - m_nextFxChannel( -1 ) + m_nextFxChannel( -1 ), + m_name( "unnamed port" ) { mixer::inst()->clearAudioBuffer( m_firstBuffer, mixer::inst()->framesPerAudioBuffer() ); mixer::inst()->clearAudioBuffer( m_secondBuffer, mixer::inst()->framesPerAudioBuffer() ); mixer::inst()->addAudioPort( this ); + setExtOutputEnabled( TRUE ); } @@ -95,6 +97,7 @@ void audioPort::setExtOutputEnabled( bool _enabled ) void audioPort::setName( const QString & _name ) { - mixer::inst()->audioDev()->renamePort( this, _name ); + m_name = _name; + mixer::inst()->audioDev()->renamePort( this ); } diff --git a/src/audio/audio_sample_recorder.cpp b/src/audio/audio_sample_recorder.cpp index f49a93756..144e6a571 100644 --- a/src/audio/audio_sample_recorder.cpp +++ b/src/audio/audio_sample_recorder.cpp @@ -96,7 +96,7 @@ void audioSampleRecorder::createSampleBuffer( sampleBuffer * * _sample_buf ) -void audioSampleRecorder::writeBufferToDev( surroundSampleFrame * _ab, +void audioSampleRecorder::writeBuffer( surroundSampleFrame * _ab, Uint32 _frames, float ) { sampleFrame * buf = bufferAllocator::alloc( _frames ); diff --git a/src/audio/audio_sdl.cpp b/src/audio/audio_sdl.cpp index 6976c1657..a2444054c 100644 --- a/src/audio/audio_sdl.cpp +++ b/src/audio/audio_sdl.cpp @@ -50,11 +50,8 @@ audioSDL::audioSDL( Uint32 _sample_rate, bool & _success_ful ) : audioDevice( _sample_rate, DEFAULT_CHANNELS ), - m_buffer( bufferAllocator::alloc( - mixer::inst()->framesPerAudioBuffer() * - channels() ) ), - m_bufMutex(), - m_callbackMutex(), + m_outBuf( bufferAllocator::alloc( + mixer::inst()->framesPerAudioBuffer() ) ), m_convertEndian( FALSE ) { _success_ful = FALSE; @@ -99,11 +96,6 @@ audioSDL::audioSDL( Uint32 _sample_rate, bool & _success_ful ) : } m_convertEndian = ( m_audioHandle.format != actual.format ); - clearS16Buffer( m_buffer, m_audioHandle.samples ); - - // start playing - SDL_PauseAudio( 0 ); - _success_ful = TRUE; } @@ -112,31 +104,31 @@ audioSDL::audioSDL( Uint32 _sample_rate, bool & _success_ful ) : audioSDL::~audioSDL() { - SDL_PauseAudio( 1 ); + stopProcessing(); SDL_CloseAudio(); SDL_Quit(); - - m_bufMutex.lock(); - bufferAllocator::free( m_buffer ); - m_bufMutex.unlock(); + bufferAllocator::free( m_outBuf ); } - -void audioSDL::writeBufferToDev( surroundSampleFrame * _ab, Uint32 _frames, - float _master_gain ) +void audioSDL::startProcessing( void ) { - m_bufMutex.lock(); - convertToS16( _ab, _frames, _master_gain, m_buffer, - m_convertEndian ); - m_bufMutex.unlock(); - // before returning make sure, callback was called, so we're synced - // with it (otherwise it could be that (if there's not much to render) - // this function is called several times although we had to wait until - // we can proceed with next audio-output) - m_callbackMutex.lock(); + SDL_PauseAudio( 0 ); + SDL_UnlockAudio(); +} + + + + +void audioSDL::stopProcessing( void ) +{ + if( SDL_GetAudioStatus() == SDL_AUDIO_PLAYING ) + { + SDL_LockAudio(); + SDL_PauseAudio( 1 ); + } } @@ -150,21 +142,12 @@ void audioSDL::sdlAudioCallback( void * _udata, Uint8 * _buf, int _len ) assert( _this != NULL ); #endif - _this->m_bufMutex.lock(); + const Uint32 frames = _this->getNextBuffer( _this->m_outBuf ); - // writeBufferToDev() prepared everything for us, so we just have - // to do a memcpy() :-) - memcpy( _buf, _this->m_buffer, _len ); - - // clear our output buffer, so that we don't output the same noise - // when being called again without that writeBufferToDev() was called - // (e.g. if there's too much to render) - _this->clearS16Buffer( _this->m_buffer, _this->m_audioHandle.samples ); - - _this->m_bufMutex.unlock(); - - // we got our last buffer, so we let writeBufferToDev() return - _this->m_callbackMutex.unlock(); + _this->convertToS16( _this->m_outBuf, frames, + mixer::inst()->masterGain(), + (outputSampleType *)( _buf ), + _this->m_convertEndian ); } diff --git a/src/core/arp_and_chords_tab_widget.cpp b/src/core/arp_and_chords_tab_widget.cpp index 610888a3d..e675a8aef 100644 --- a/src/core/arp_and_chords_tab_widget.cpp +++ b/src/core/arp_and_chords_tab_widget.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #define setChecked setOn diff --git a/src/core/bb_editor.cpp b/src/core/bb_editor.cpp index 24fb6540c..3d163edc4 100644 --- a/src/core/bb_editor.cpp +++ b/src/core/bb_editor.cpp @@ -30,10 +30,12 @@ #include #include #include +#include #else #include +#include #endif @@ -41,13 +43,12 @@ #include "bb_editor.h" #include "song_editor.h" #include "embed.h" -#include "pixmap_button.h" +#include "tool_button.h" #include "track_container.h" #include "bb_track.h" #include "name_label.h" #include "templates.h" #include "debug.h" -#include "spc_bg_hndl_widget.h" #include "tooltip.h" @@ -57,18 +58,22 @@ const int BBE_PPT = 192; bbEditor * bbEditor::s_instanceOfMe = NULL; -QPixmap * bbEditor::s_titleArtwork = NULL; bbEditor::bbEditor() : trackContainer() { - if( s_titleArtwork == NULL ) - { - s_titleArtwork = new QPixmap( embed::getIconPixmap( - "bb_editor_title_artwork" ) ); - } + // create toolbar + m_toolBar = new QWidget( this ); + m_toolBar->setFixedHeight( 32 ); + m_toolBar->move( 0, 0 ); + m_toolBar->setPaletteBackgroundPixmap( embed::getIconPixmap( + "toolbar_bg" ) ); + + QHBoxLayout * tb_layout = new QHBoxLayout( m_toolBar ); + + setWindowIcon( embed::getIconPixmap( "bb_track" ) ); setWindowTitle( tr( "Beat+Bassline Editor" ) ); @@ -83,33 +88,19 @@ bbEditor::bbEditor() : setGeometry( 210, 340, minimumWidth(), 300 ); } - containerWidget()->move( 0, 47 ); + containerWidget()->move( 0, 32 ); setPixelsPerTact( BBE_PPT ); - updateBackground(); - - m_playButton = new pixmapButton( this ); - m_playButton->move( 96, 7 ); - m_playButton->setCheckable( FALSE ); - m_playButton->setActiveGraphic( embed::getIconPixmap( "play" ) ); - m_playButton->setInactiveGraphic( embed::getIconPixmap( "play" ) ); - m_playButton->setBgGraphic( specialBgHandlingWidget::getBackground( - m_playButton ) ); - connect( m_playButton, SIGNAL( clicked() ), this, SLOT( play() ) ); - - m_stopButton = new pixmapButton( this ); - m_stopButton->move( 136, 7 ); - m_stopButton->setCheckable( FALSE ); - m_stopButton->setActiveGraphic( embed::getIconPixmap( "stop" ) ); - m_stopButton->setInactiveGraphic( embed::getIconPixmap( "stop" ) ); - m_stopButton->setBgGraphic( specialBgHandlingWidget::getBackground( - m_playButton ) ); - connect( m_stopButton, SIGNAL( clicked() ), this, SLOT( stop() ) ); - toolTip::add( m_playButton, - tr( "Play/pause current beat/bassline (Space)" ) ); - toolTip::add( m_stopButton, - tr( "Stop playing of current beat/bassline (Space)" ) ); + m_playButton = new toolButton( embed::getIconPixmap( "play" ), + tr( "Play/pause current beat/bassline (Space)" ), + this, SLOT( play() ), m_toolBar ); + + m_stopButton = new toolButton( embed::getIconPixmap( "stop" ), + tr( "Stop playing of current beat/bassline (Space)" ), + this, SLOT( stop() ), m_toolBar ); + + #ifdef QT4 m_playButton->setWhatsThis( #else @@ -126,9 +117,15 @@ bbEditor::bbEditor() : tr( "Click here, if you want to stop playing of current " "beat/bassline." ) ); -#ifndef QT4 - setBackgroundMode( Qt::NoBackground ); -#endif + QLabel * l = new QLabel( m_toolBar ); + l->setPixmap( embed::getIconPixmap( "drum" ) ); + + tb_layout->addSpacing( 5 ); + tb_layout->addWidget( m_playButton ); + tb_layout->addWidget( m_stopButton ); + tb_layout->addStretch(); + tb_layout->addWidget( l ); + tb_layout->addSpacing( 15 ); show(); } @@ -305,39 +302,11 @@ void bbEditor::keyPressEvent( QKeyEvent * _ke ) void bbEditor::resizeEvent( QResizeEvent * _re ) { - updateBackground(); setPixelsPerTact( width() - ( TRACK_OP_WIDTH + DEFAULT_SETTINGS_WIDGET_WIDTH + 2 * TCO_BORDER_WIDTH ) ); trackContainer::resizeEvent( _re ); -} - - - - -void bbEditor::updateBackground( void ) -{ - QPixmap draw_pm( size() ); -#ifdef QT4 - draw_pm.fill( containerWidget()->palette().brush( - containerWidget()->backgroundRole() ).color() ); -#else - draw_pm.fill( containerWidget()->paletteBackgroundColor() ); -#endif - - QPainter p( &draw_pm ); - - p.fillRect( 0, 0, width(), s_titleArtwork->height(), - QColor( 74, 125, 213 ) ); - p.drawPixmap( 0, 0, *s_titleArtwork ); - -#ifdef QT4 - QPalette pal = palette(); - pal.setBrush( backgroundRole(), QBrush( draw_pm ) ); - setPalette( pal ); -#else - setErasePixmap( draw_pm ); -#endif + m_toolBar->setFixedWidth( width() ); } @@ -351,26 +320,24 @@ void bbEditor::play( void ) { songEditor::inst()->stop(); songEditor::inst()->playBB(); - m_playButton->setInactiveGraphic( - embed::getIconPixmap( "pause" ) ); + m_playButton->setPixmap( embed::getIconPixmap( + "pause" ) ); } else { songEditor::inst()->pause(); - m_playButton->setInactiveGraphic( - embed::getIconPixmap( "play" ) ); + m_playButton->setPixmap( embed::getIconPixmap( + "play" ) ); } } else if( songEditor::inst()->paused() ) { songEditor::inst()->resumeFromPause(); - m_playButton->setInactiveGraphic( - embed::getIconPixmap( "pause" ) ); + m_playButton->setPixmap( embed::getIconPixmap( "pause" ) ); } else { - m_playButton->setInactiveGraphic( - embed::getIconPixmap( "pause" ) ); + m_playButton->setPixmap( embed::getIconPixmap( "pause" ) ); songEditor::inst()->playBB(); } @@ -382,7 +349,7 @@ void bbEditor::play( void ) void bbEditor::stop( void ) { songEditor::inst()->stop(); - m_playButton->setInactiveGraphic( embed::getIconPixmap( "play" ) ); + m_playButton->setPixmap( embed::getIconPixmap( "play" ) ); m_playButton->update(); } diff --git a/src/core/config_mgr.cpp b/src/core/config_mgr.cpp index 7a673fa86..87806db87 100644 --- a/src/core/config_mgr.cpp +++ b/src/core/config_mgr.cpp @@ -740,7 +740,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 ) && @@ -771,7 +771,7 @@ bool configManager::loadConfigFile( void ) return( loadConfigFile() ); } } - } + }*/ QDomNode node = root.firstChild(); diff --git a/src/core/export_project_dialog.cpp b/src/core/export_project_dialog.cpp index ac55707c1..bcb5256c0 100644 --- a/src/core/export_project_dialog.cpp +++ b/src/core/export_project_dialog.cpp @@ -32,10 +32,10 @@ #include #include #include -#include #include #include #include +#include #else @@ -44,21 +44,25 @@ #include #include #include -#include #include #include +#include #endif #include "export_project_dialog.h" #include "song_editor.h" +#include "lmms_main_win.h" #include "embed.h" #include "audio_file_wave.h" #include "audio_file_ogg.h" +extern QString file_to_render; + + fileEncodeDevice fileEncodeDevices[] = { @@ -129,9 +133,7 @@ exportProjectDialog::exportProjectDialog( const QString & _file_name, QDialog( _parent ), m_fileName( _file_name ), m_hourglassLbl( NULL ), - m_exportProgressBar( NULL ), - m_deleteFile( FALSE ), - m_oldProgressVal( -1 ) + m_deleteFile( FALSE ) { #ifdef QT4 m_fileType = getFileTypeFromExtension( "." + @@ -312,35 +314,6 @@ void exportProjectDialog::exportBtnClicked( void ) { if( fileEncodeDevices[idx].m_fileType == m_fileType ) { - bool success_ful = FALSE; - audioDevice * dev = fileEncodeDevices[idx].m_getDevInst( - DEFAULT_SAMPLE_RATE, - DEFAULT_CHANNELS, - success_ful, - m_fileName, - m_vbrCb->isChecked(), - m_kbpsCombo->currentText().toInt(), - m_kbpsCombo->currentText().toInt() - 64, - m_kbpsCombo->currentText().toInt() + 64 - ); - if( success_ful == FALSE ) - { - QMessageBox::information( this, - tr( "Export failed" ), - tr( "The project-export failed, " - "because the output-file/-" - "device could not be opened.\n" - "Make sure, you have write " - "access to the selected " - "file/device!" ), - QMessageBox::Ok ); - return; - } - mixer::inst()->pause(); - mixer::inst()->setAudioDevice( dev, - m_hqmCb->isChecked() ); - songEditor::inst()->startExport(); - mixer::inst()->play(); break; } ++idx; @@ -351,6 +324,32 @@ void exportProjectDialog::exportBtnClicked( void ) return; } + bool success_ful = FALSE; + audioFileDevice * dev = fileEncodeDevices[idx].m_getDevInst( + DEFAULT_SAMPLE_RATE, + DEFAULT_CHANNELS, + success_ful, + m_fileName, + m_vbrCb->isChecked(), + m_kbpsCombo->currentText().toInt(), + m_kbpsCombo->currentText().toInt() - 64, + m_kbpsCombo->currentText().toInt() + 64 + ); + if( success_ful == FALSE ) + { + QMessageBox::information( this, + tr( "Export failed" ), + tr( "The project-export failed, " + "because the output-file/-" + "device could not be opened.\n" + "Make sure, you have write " + "access to the selected " + "file/device!" ), + QMessageBox::Ok ); + return; + } + + setWindowTitle( tr( "Exporting project to %1" ).arg( QFileInfo( m_fileName ).fileName() ) ); @@ -379,11 +378,40 @@ void exportProjectDialog::exportBtnClicked( void ) m_cancelBtn->move( CANCEL_X_WHILE_EXPORT, CANCEL_Y_WHILE_EXPORT ); - m_progressBarUpdateTimer = new QTimer( this ); - connect( m_progressBarUpdateTimer, SIGNAL( timeout() ), this, - SLOT( redrawProgressBar() ) ); - m_progressBarUpdateTimer->start( 100 ); + + mixer::inst()->setAudioDevice( dev, m_hqmCb->isChecked() ); + songEditor::inst()->startExport(); + + + songEditor::playPos & pp = songEditor::inst()->getPlayPos( + songEditor::PLAY_SONG ); + + while( songEditor::inst()->exportDone() == FALSE && + songEditor::inst()->exporting() == TRUE ) + { + dev->processNextBuffer(); + int pval = pp * 100 / + ( ( songEditor::inst()->lengthInTacts() + 1 ) * 64 ); +#ifdef QT4 + m_exportProgressBar->setValue( pval ); +#else + m_exportProgressBar->setProgress( pval ); +#endif + // update lmms-main-win-caption + lmmsMainWin::inst()->setWindowTitle( tr( "Rendering:" ) + " " + + QString::number( pval ) + "%" ); + // process paint-events etc. + qApp->processEvents(); + } + + // if m_deleteFile == TRUE, user aborted export and finalization- + // routines were already called, so we only need to call them if + // export went through without any problems + if( m_deleteFile == FALSE ) + { + finishProjectExport(); + } } @@ -398,19 +426,6 @@ void exportProjectDialog::cancelBtnClicked( void ) abortProjectExport(); return; } - - // if the user aborted export-process, the file has to be deleted - if( m_deleteFile ) - { - QFile( m_fileName ).remove(); - } - - // restore window-title - lmmsMainWin::inst()->resetWindowTitle(); - - // let's close us... - accept(); - } @@ -419,7 +434,6 @@ void exportProjectDialog::cancelBtnClicked( void ) // called whenever there's a reason for aborting song-export (like user-input) void exportProjectDialog::abortProjectExport( void ) { - mixer::inst()->pause(); m_deleteFile = TRUE; finishProjectExport(); @@ -430,53 +444,32 @@ void exportProjectDialog::abortProjectExport( void ) void exportProjectDialog::finishProjectExport( void ) { - m_progressBarUpdateTimer->stop(); - delete m_progressBarUpdateTimer; - mixer::inst()->restoreAudioDevice(); + + // if the user aborted export-process, the file has to be deleted + if( m_deleteFile ) + { + QFile( m_fileName ).remove(); + } + + // restore window-title + lmmsMainWin::inst()->resetWindowTitle(); + songEditor::inst()->stopExport(); - mixer::inst()->play(); - - // this method does the final cleanup... - cancelBtnClicked(); -} - - - - -void exportProjectDialog::redrawProgressBar( void ) -{ - if( m_progressVal != m_oldProgressVal ) + // if we rendered file from command line, quit after export + if( file_to_render != "" ) { -#ifdef QT4 - m_exportProgressBar->setValue( m_progressVal ); -#else - m_exportProgressBar->setProgress( m_progressVal ); -#endif - // update lmms-main-win-caption - lmmsMainWin::inst()->setWindowTitle( tr( "Rendering:" ) + " " + - QString::number( m_progressVal ) + "%" ); - m_oldProgressVal = m_progressVal; - } - - if( songEditor::inst()->exportDone() == TRUE || - songEditor::inst()->exporting() == FALSE ) - { - finishProjectExport(); + // qApp->quit(); - doesn't work for some reason... + exit( 0 ); } + // let's close us... + accept(); } -void exportProjectDialog::updateProgressBar( int _new_val ) -{ - m_progressVal = _new_val; -} - - - #include "export_project_dialog.moc" diff --git a/src/core/main.cpp b/src/core/main.cpp index a18c069e5..28e23d47b 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -61,17 +61,37 @@ int main( int argc, char * * argv ) { QApplication app( argc, argv ); + QString extension = "wav"; + for( int i = 1; i < app.argc(); ++i ) { if( QString( app.argv()[i] ) == "--version" || QString( app.argv()[i] ) == "-v" ) { - printf( "\n%s\n\n" + printf( "\nLinux MultiMedia Studio %s\n\n" + "Copyright (c) 2004-2005 Tobias Doerffel and others.\n\n" "This program is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU General Public\n" "License as published by the Free Software Foundation; either\n" - "version 2 of the License, or (at your option) any later version.\n\n", - PACKAGE_STRING ); + "version 2 of the License, or (at your option) any later version.\n\n" + "Try \"%s --help\" for more information.\n\n", PACKAGE_VERSION, + argv[0] ); + return( 0 ); + } + else if( app.argc() > i && + ( QString( app.argv()[i] ) == "--help" || + QString( app.argv()[i] ) == "-h" ) ) + { + printf( "\nLinux MultiMedia Studio %s\n" + "Copyright (c) 2004-2005 Tobias Doerffel and others.\n\n" + "usage: lmms [ -r [ -o ] [ -h ] " + "[ ]\n" + "-r, --render render given file.\n" + "-o, --output-format specify format of render-output where\n" + " format is either 'wav' or 'ogg'.\n" + "-v, --version show version information and exit.\n" + "-h, --help show this usage message and exit.\n\n", + PACKAGE_VERSION ); return( 0 ); } else if( app.argc() > i && @@ -79,14 +99,42 @@ int main( int argc, char * * argv ) QString( app.argv()[i] ) == "-r" ) ) { file_to_load = QString( app.argv()[i+1] ); - file_to_render = QString( app.argv()[i+1] ) + ".wav"; + file_to_render = baseName( file_to_load ) + "."; + ++i; + } + else if( app.argc() > i && + ( QString( app.argv()[i] ) == "--output-format" || + QString( app.argv()[i] ) == "-o" ) ) + { + extension = QString( app.argv()[i+1] ); + if( extension != "wav" && extension != "ogg" ) + { + printf( "\nInvalid output format %s.\n\n" + "Try \"%s --help\" for more information.\n\n", app.argv()[i+1], + argv[0] ); + return( -1 ); + } + ++i; } else { + if( app.argv()[i][0] == '-' ) + { + printf( "\nInvalid option %s.\n\n" + "Try \"%s --help\" for more information.\n\n", app.argv()[i], + argv[0] ); + return( -1 ); + } file_to_load = app.argv()[i]; } } + if( file_to_render != "" ) + { + file_to_render += extension; + } + + QString pos = #ifdef QT4 QLocale::system().name().left( 2 ); @@ -172,7 +220,6 @@ int main( int argc, char * * argv ) exportProjectDialog * e = new exportProjectDialog( file_to_render, lmmsMainWin::inst() ); - songEditor::inst()->setExportProjectDialog( e ); e->show(); e->exportBtnClicked(); } diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index adea1b3fe..ce3a6b1f2 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -57,21 +57,12 @@ mixer * mixer::s_instanceOfMe = NULL; mixer::mixer() : -#ifndef QT4 QObject(), -#endif - QThread(), -/* m_silence(), -#ifndef DISABLE_SURROUND - m_surroundSilence(), -#endif*/ m_framesPerAudioBuffer( DEFAULT_BUFFER_SIZE ), m_curBuf( NULL ), m_nextBuf( NULL ), - m_discardCurBuf( FALSE ), m_qualityLevel( DEFAULT_QUALITY_LEVEL ), - m_masterOutput( 1.0f ), - m_quit( FALSE ), + m_masterGain( 1.0f ), m_audioDev( NULL ), m_oldAudioDev( NULL ) { @@ -101,30 +92,12 @@ mixer::mixer() : m_midiClient = tryMIDIClients(); -/* m_silence = bufferAllocator::alloc( - m_framesPerAudioBuffer ); -#ifndef DISABLE_SURROUND - m_surroundSilence = bufferAllocator::alloc( - m_framesPerAudioBuffer ); -#endif - for( Uint32 frame = 0; frame < m_framesPerAudioBuffer; ++frame ) - { - for( Uint8 chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl ) - { - m_silence[frame][chnl] = 0.0f; - } -#ifndef DISABLE_SURROUND - for( Uint8 chnl = 0; chnl < SURROUND_CHANNELS; ++chnl ) - { - m_surroundSilence[frame][chnl] = 0.0f; - } -#endif - }*/ - // now clear our two output-buffers before using them... clearAudioBuffer( m_curBuf, m_framesPerAudioBuffer ); clearAudioBuffer( m_nextBuf, m_framesPerAudioBuffer ); + m_audioDev->startProcessing(); + } @@ -137,132 +110,98 @@ mixer::~mixer() bufferAllocator::free( m_curBuf ); bufferAllocator::free( m_nextBuf ); - - -/* bufferAllocator::free( m_silence ); -#ifndef DISABLE_SURROUND - bufferAllocator::free( m_surroundSilence ); -#endif*/ } -void mixer::quitThread( void ) +void mixer::stopProcessing( void ) { - // make sure there're no mutexes locked anymore... - m_safetySyncMutex.unlock(); - m_devMutex.unlock(); - - // now tell mixer-thread to quit - m_quit = TRUE; - - wait( 1000 ); - terminate(); + m_audioDev->stopProcessing(); } -void mixer::run( void ) +const surroundSampleFrame * mixer::renderNextBuffer( void ) { - - while( m_quit == FALSE ) + // remove all play-handles that have to be deleted and delete + // them if they still exist... + // maybe this algorithm could be optimized... + while( !m_playHandlesToRemove.empty() ) { + playHandleVector::iterator it = m_playHandles.begin(); - // remove all play-handles that have to be deleted and delete - // them if they still exist... - // maybe this algorithm could be optimized... - while( !m_playHandlesToRemove.empty() ) + while( it != m_playHandles.end() ) { - playHandleVector::iterator it = m_playHandles.begin(); - - while( it != m_playHandles.end() ) + if( *it == m_playHandlesToRemove.front() ) { - if( *it == m_playHandlesToRemove.front() ) - { - m_playHandles.erase( it ); - delete m_playHandlesToRemove.front(); - break; - } - ++it; + m_playHandles.erase( it ); + delete m_playHandlesToRemove.front(); + break; } - - m_playHandlesToRemove.erase( - m_playHandlesToRemove.begin() ); - + ++it; } - // now we have to make sure no other thread does anything bad - // while we're acting... - m_safetySyncMutex.lock(); + m_playHandlesToRemove.erase( + m_playHandlesToRemove.begin() ); + } - csize idx = 0; - while( idx < m_playHandles.size() ) + // now we have to make sure no other thread does anything bad + // while we're acting... + m_mixMutex.lock(); + + // now swap the buffers... current buffer becomes next (last) + // buffer and the next buffer becomes current (first) buffer + qSwap( m_curBuf, m_nextBuf ); + + // clear last audio-buffer + clearAudioBuffer( m_curBuf, m_framesPerAudioBuffer ); + + + csize idx = 0; + while( idx < m_playHandles.size() ) + { + register playHandle * n = m_playHandles[idx]; + if( n->done() ) { - register playHandle * n = m_playHandles[idx]; - if( n->done() ) - { - // delete all play-handles which have - // played completely now - delete n; - m_playHandles.erase( m_playHandles.begin() + - idx ); - } - else - { - // play all uncompletely-played play-handles... - n->play(); - ++idx; - } - } - - songEditor::inst()->processNextBuffer(); - - for( vvector::iterator it = m_audioPorts.begin(); - it != m_audioPorts.end(); ++it ) - { - if( ( *it )->m_bufferUsage != audioPort::NONE ) - { - processBuffer( ( *it )->firstBuffer(), - ( *it )->nextFxChannel() ); - ( *it )->nextPeriod(); - } - } - - if( !m_discardCurBuf ) - { - m_devMutex.lock(); - // write actual data to our current output-device - // (blocking!) - m_audioDev->writeBuffer( m_curBuf, - m_framesPerAudioBuffer, - SAMPLE_RATES[m_qualityLevel], - m_masterOutput ); - m_devMutex.unlock(); + // delete all play-handles which have + // played completely now + delete n; + m_playHandles.erase( m_playHandles.begin() + + idx ); } else { - m_discardCurBuf = FALSE; + // play all uncompletely-played play-handles... + n->play(); + ++idx; } - - emit nextAudioBuffer( m_curBuf, m_framesPerAudioBuffer ); - usleep( 1 ); // give time to other threads/processes - - m_safetySyncMutex.unlock(); - - - // clear last audio-buffer - clearAudioBuffer( m_curBuf, m_framesPerAudioBuffer ); - - // now swap the buffers... current buffer becomes next (last) - // buffer and the next buffer becomes current (first) buffer - qSwap( m_curBuf, m_nextBuf ); - - // and trigger LFOs - envelopeAndLFOWidget::triggerLFO(); } + songEditor::inst()->processNextBuffer(); + + for( vvector::iterator it = m_audioPorts.begin(); + it != m_audioPorts.end(); ++it ) + { + if( ( *it )->m_bufferUsage != audioPort::NONE ) + { + processBuffer( ( *it )->firstBuffer(), + ( *it )->nextFxChannel() ); + ( *it )->nextPeriod(); + } + } + + + emit nextAudioBuffer( m_curBuf, m_framesPerAudioBuffer ); + + m_mixMutex.unlock(); + + + // and trigger LFOs + envelopeAndLFOWidget::triggerLFO(); + + return( m_curBuf ); } @@ -286,21 +225,6 @@ void mixer::clear( void ) void FASTCALL mixer::clearAudioBuffer( sampleFrame * _ab, Uint32 _frames ) { memset( _ab, 0, sizeof( *_ab ) * _frames ); -/* if( _frames == m_framesPerAudioBuffer ) - { - memcpy( _ab, m_silence, m_framesPerAudioBuffer * - BYTES_PER_FRAME ); - } - else - { - for( Uint32 frame = 0; frame < _frames; ++frame ) - { - for( Uint8 ch = 0; ch < DEFAULT_CHANNELS; ++ch ) - { - _ab[frame][ch] = 0.0f; - } - } - }*/ } @@ -310,21 +234,6 @@ void FASTCALL mixer::clearAudioBuffer( surroundSampleFrame * _ab, Uint32 _frames ) { memset( _ab, 0, sizeof( *_ab ) * _frames ); -/* if( _frames == m_framesPerAudioBuffer ) - { - memcpy( _ab, m_surroundSilence, m_framesPerAudioBuffer * - BYTES_PER_SURROUND_FRAME ); - } - else - { - for( Uint32 frame = 0; frame < _frames; ++frame ) - { - for( Uint8 ch = 0; ch < DEFAULT_CHANNELS; ++ch ) - { - _ab[frame][ch] = 0.0f; - } - } - }*/ } #endif @@ -377,8 +286,6 @@ void FASTCALL mixer::bufferToPort( sampleFrame * _buf, Uint32 _frames, void mixer::setHighQuality( bool _hq_on ) { - m_safetySyncMutex.lock(); - // delete (= close) our audio-device delete m_audioDev; @@ -393,8 +300,7 @@ void mixer::setHighQuality( bool _hq_on ) } // and re-open device m_audioDev = tryAudioDevices(); - - m_safetySyncMutex.unlock(); + m_audioDev->startProcessing(); emit( sampleRateChanged() ); @@ -405,8 +311,7 @@ void mixer::setHighQuality( bool _hq_on ) void FASTCALL mixer::setAudioDevice( audioDevice * _dev, bool _hq ) { - - m_devMutex.lock(); + m_audioDev->stopProcessing(); m_oldAudioDev = m_audioDev; @@ -423,9 +328,6 @@ void FASTCALL mixer::setAudioDevice( audioDevice * _dev, bool _hq ) m_qualityLevel = _hq ? 1 : 0; emit sampleRateChanged(); - - m_devMutex.unlock(); - } @@ -433,11 +335,10 @@ void FASTCALL mixer::setAudioDevice( audioDevice * _dev, bool _hq ) void mixer::restoreAudioDevice( void ) { - m_devMutex.lock(); - if( m_oldAudioDev != NULL ) { - delete m_audioDev; + delete m_audioDev; // dtor automatically calls + // stopProcessing() m_audioDev = m_oldAudioDev; for( Uint8 qli = 0; qli < QUALITY_LEVELS; ++qli ) { @@ -449,10 +350,8 @@ void mixer::restoreAudioDevice( void ) } } m_oldAudioDev = NULL; - m_discardCurBuf = TRUE; + m_audioDev->startProcessing(); } - - m_devMutex.unlock(); } @@ -474,8 +373,6 @@ void mixer::checkValidityOfPlayHandles( void ) audioDevice * mixer::tryAudioDevices( void ) { - //m_discardCurBuf = TRUE; - bool success_ful = FALSE; audioDevice * dev = NULL; QString dev_name = configManager::inst()->value( "mixer", "audiodev" ); diff --git a/src/core/piano_roll.cpp b/src/core/piano_roll.cpp index daa9e02a4..fe2a85bf4 100644 --- a/src/core/piano_roll.cpp +++ b/src/core/piano_roll.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #else @@ -41,6 +42,7 @@ #include #include #include +#include #define setChecked setOn @@ -56,9 +58,9 @@ #include "piano_roll.h" #include "song_editor.h" +#include "lmms_main_win.h" #include "pattern.h" #include "embed.h" -#include "crystal_button.h" #include "pixmap_button.h" #include "templates.h" #include "gui_templates.h" @@ -66,6 +68,7 @@ #include "channel_track.h" #include "tooltip.h" #include "midi.h" +#include "tool_button.h" extern tones whiteKeys[]; // defined in piano_widget.cpp @@ -88,7 +91,7 @@ const int KEY_LINE_HEIGHT = 12; const int OCTAVE_HEIGHT = KEY_LINE_HEIGHT * NOTES_PER_OCTAVE; // = 12 * 12; const int PR_BOTTOM_MARGIN = SCROLLBAR_SIZE; -const int PR_TOP_MARGIN = 66; +const int PR_TOP_MARGIN = 48; // width of area used for resizing (the grip at the end of a note) const int RESIZE_AREA_WIDTH = 3; @@ -106,8 +109,6 @@ pianoRoll * pianoRoll::s_instanceOfMe = NULL; QPixmap * pianoRoll::s_whiteKeySmallPm = NULL; QPixmap * pianoRoll::s_whiteKeyBigPm = NULL; QPixmap * pianoRoll::s_blackKeyPm = NULL; -QPixmap * pianoRoll::s_artwork1 = NULL; -QPixmap * pianoRoll::s_artwork2 = NULL; QPixmap * pianoRoll::s_toolDraw = NULL; QPixmap * pianoRoll::s_toolErase = NULL; QPixmap * pianoRoll::s_toolSelect = NULL; @@ -160,16 +161,6 @@ pianoRoll::pianoRoll( void ) : s_blackKeyPm = new QPixmap( embed::getIconPixmap( "pr_black_key" ) ); } - if( s_artwork1 == NULL ) - { - s_artwork1 = new QPixmap( embed::getIconPixmap( - "pr_artwork1" ) ); - } - if( s_artwork2 == NULL ) - { - s_artwork2 = new QPixmap( embed::getIconPixmap( - "pr_artwork2" ) ); - } if( s_toolDraw == NULL ) { s_toolDraw = new QPixmap( embed::getIconPixmap( @@ -196,39 +187,39 @@ pianoRoll::pianoRoll( void ) : lmmsMainWin::inst()->workspace()->addWindow( this ); #endif + // add time-line + m_timeLine = new timeLine( WHITE_KEY_WIDTH, 32, m_ppt, + songEditor::inst()->getPlayPos( + songEditor::PLAY_PATTERN ), + m_currentPosition, this ); + connect( this, SIGNAL( positionChanged( const midiTime & ) ), + m_timeLine, SLOT( updatePosition( const midiTime & ) ) ); + connect( m_timeLine, SIGNAL( positionChanged( const midiTime & ) ), + this, SLOT( updatePosition( const midiTime & ) ) ); + + + m_toolBar = new QWidget( this ); + m_toolBar->setFixedHeight( 32 ); + m_toolBar->move( 0, 0 ); + m_toolBar->setPaletteBackgroundPixmap( embed::getIconPixmap( + "toolbar_bg" ) ); + + QHBoxLayout * tb_layout = new QHBoxLayout( m_toolBar ); + + // init control-buttons at the top - m_playButton = new pixmapButton( this ); - m_playButton->move( 8, 7 ); - m_playButton->setCheckable( FALSE ); - m_playButton->setActiveGraphic( embed::getIconPixmap( "play" ) ); - m_playButton->setInactiveGraphic( embed::getIconPixmap( "play" ) ); - m_playButton->setBgGraphic( embed::getIconPixmap( "pr_play_ctrl_bg" ) ); - connect( m_playButton, SIGNAL( clicked() ), this, SLOT( play() ) ); - m_recordButton = new pixmapButton( this ); - m_recordButton->move( 50, 7 ); - m_recordButton->setCheckable( FALSE ); - m_recordButton->setActiveGraphic( embed::getIconPixmap( "record" ) ); - m_recordButton->setInactiveGraphic( embed::getIconPixmap( "record" ) ); - m_recordButton->setBgGraphic( - embed::getIconPixmap( "pr_play_ctrl_bg" ) ); - connect( m_recordButton, SIGNAL( clicked() ), this, SLOT( record() ) ); + m_playButton = new toolButton( embed::getIconPixmap( "play" ), + tr( "Play/pause current pattern (Space)" ), + this, SLOT( play() ), m_toolBar ); - m_stopButton = new pixmapButton( this ); - m_stopButton->move( 92, 7 ); - m_stopButton->setCheckable( FALSE ); - m_stopButton->setActiveGraphic( embed::getIconPixmap( "stop" ) ); - m_stopButton->setInactiveGraphic( embed::getIconPixmap( "stop" ) ); - m_stopButton->setBgGraphic( embed::getIconPixmap( "pr_play_ctrl_bg" ) ); - connect( m_stopButton, SIGNAL( clicked() ), this, SLOT( stop() ) ); + m_recordButton = new toolButton( embed::getIconPixmap( "record" ), + tr( "Record notes from MIDI-device/channel-piano" ), + this, SLOT( record() ), m_toolBar ); - toolTip::add( m_playButton, - tr( "Play/pause current pattern (Space)" ) ); - toolTip::add( m_recordButton, - tr( "Record notes from MIDI-device to current " - "pattern" ) ); - toolTip::add( m_stopButton, - tr( "Stop playing of current pattern (Space)" ) ); + m_stopButton = new toolButton( embed::getIconPixmap( "stop" ), + tr( "Stop playing of current pattern (Space)" ), + this, SLOT( stop() ), m_toolBar ); #ifdef QT4 m_playButton->setWhatsThis( @@ -246,8 +237,8 @@ pianoRoll::pianoRoll( void ) : tr( "Click here, if you want to record notes from a MIDI-" "device or the virtual test-piano of the according " "channel-window to the current pattern. When recording " - "all notes you play will be written to this pattern " - "and you can edit, play etc. them afterwards." ) ); + "all notes you play will be written to this pattern " + "and you can play and edit them afterwards." ) ); #ifdef QT4 m_stopButton->setWhatsThis( #else @@ -269,33 +260,31 @@ pianoRoll::pianoRoll( void ) : SLOT( verScrolled( int ) ) ); // init edit-buttons at the top - m_drawButton = new crystalButton( embed::getIconPixmap( "pr_tool_bg" ), - embed::getIconPixmap( - "pr_tool_draw" ), this ); - m_drawButton->move( 170, 1 ); - m_drawButton->setActiveButtonBg( embed::getIconPixmap( - "pr_tool_bg_inset" ) ); + m_drawButton = new toolButton( embed::getIconPixmap( "pr_tool_draw" ), + tr( "Draw mode (D)" ), + this, SLOT( drawButtonToggled() ), + m_toolBar ); + m_drawButton->setCheckable( TRUE ); m_drawButton->setChecked( TRUE ); - m_eraseButton = new crystalButton( embed::getIconPixmap( "pr_tool_bg" ), - embed::getIconPixmap( - "pr_tool_erase" ), this ); - m_eraseButton->move( 220, 1 ); - m_eraseButton->setActiveButtonBg( embed::getIconPixmap( - "pr_tool_bg_inset" ) ); - m_selectButton = new crystalButton( embed::getIconPixmap( - "pr_tool_bg" ), - embed::getIconPixmap( - "pr_tool_select" ), this ); - m_selectButton->move( 270, 1 ); - m_selectButton->setActiveButtonBg( embed::getIconPixmap( - "pr_tool_bg_inset" ) ); - m_moveButton = new crystalButton( embed::getIconPixmap( "pr_tool_bg" ), - embed::getIconPixmap( - "pr_tool_move" ), this ); - m_moveButton->move( 320, 1 ); - m_moveButton->setActiveButtonBg( embed::getIconPixmap( - "pr_tool_bg_inset" ) ); + m_eraseButton = new toolButton( embed::getIconPixmap( "pr_tool_erase" ), + tr( "Erase mode (E)" ), + this, SLOT( eraseButtonToggled() ), + m_toolBar ); + m_eraseButton->setCheckable( TRUE ); + + m_selectButton = new toolButton( embed::getIconPixmap( + "pr_tool_select" ), + tr( "Select mode (S)" ), + this, SLOT( selectButtonToggled() ), + m_toolBar ); + m_selectButton->setCheckable( TRUE ); + + m_moveButton = new toolButton( embed::getIconPixmap( "pr_tool_move" ), + tr( "Move selection mode (M)" ), + this, SLOT( moveButtonToggled() ), + m_toolBar ); + m_moveButton->setCheckable( TRUE ); QButtonGroup * tool_button_group = new QButtonGroup( this ); tool_button_group->addButton( m_drawButton ); @@ -307,26 +296,6 @@ pianoRoll::pianoRoll( void ) : tool_button_group->hide(); #endif - connect( m_drawButton, SIGNAL( toggled( bool ) ), this, - SLOT( drawButtonToggled( bool ) ) ); - connect( m_eraseButton, SIGNAL( toggled( bool ) ), this, - SLOT( eraseButtonToggled( bool ) ) ); - connect( m_selectButton, SIGNAL( toggled( bool ) ), this, - SLOT( selectButtonToggled( bool ) ) ); - connect( m_moveButton, SIGNAL( toggled( bool ) ), this, - SLOT( moveButtonToggled( bool ) ) ); - - toolTip::add( m_drawButton, - tr( "Click if you want to draw, resize or move single " - "notes (= key 'D')" ) ); - toolTip::add( m_eraseButton, - tr( "Click if you want to erase single notes " - "(= key 'E')" ) ); - toolTip::add( m_selectButton, - tr( "Click if you want to select notes (= key 'S')" ) ); - toolTip::add( m_moveButton, - tr( "Click if you want to move selected notes " - "(= key 'M')" ) ); #ifdef QT4 m_drawButton->setWhatsThis( #else @@ -365,42 +334,22 @@ pianoRoll::pianoRoll( void ) : "mode. You can also press 'M' on your keyboard to " "activate this mode." ) ); + m_cutButton = new toolButton( embed::getIconPixmap( "edit_cut" ), + tr( "Cut selected notes (Ctrl+X)" ), + this, SLOT( cutSelectedNotes() ), + m_toolBar ); - m_cutButton = new crystalButton( embed::getIconPixmap( "pr_tool_bg" ), - embed::getIconPixmap( - "pr_edit_cut" ), this ); - m_cutButton->move( 390, 1 ); - m_cutButton->setActiveButtonBg( embed::getIconPixmap( - "pr_tool_bg_inset" ) ); - m_cutButton->setCheckable( FALSE ); - m_copyButton = new crystalButton( embed::getIconPixmap( "pr_tool_bg" ), - embed::getIconPixmap( - "pr_edit_copy" ), - this ); - m_copyButton->move( 440, 1 ); - m_copyButton->setActiveButtonBg( embed::getIconPixmap( - "pr_tool_bg_inset" ) ); - m_copyButton->setCheckable( FALSE ); - m_pasteButton = new crystalButton( embed::getIconPixmap( "pr_tool_bg" ), - embed::getIconPixmap( - "pr_edit_paste" ), - this ); - m_pasteButton->move( 490, 1 ); - m_pasteButton->setActiveButtonBg( embed::getIconPixmap( - "pr_tool_bg_inset" ) ); - m_pasteButton->setCheckable( FALSE ); + m_copyButton = new toolButton( embed::getIconPixmap( "edit_copy" ), + tr( "Copy selected notes (Ctrl+C)" ), + this, SLOT( copySelectedNotes() ), + m_toolBar ); - connect( m_cutButton, SIGNAL( clicked() ), this, - SLOT( cutSelectedNotes() ) ); - connect( m_copyButton, SIGNAL( clicked() ), this, - SLOT( copySelectedNotes() ) ); - connect( m_pasteButton, SIGNAL( clicked() ), this, - SLOT( pasteNotes() ) ); + m_pasteButton = new toolButton( embed::getIconPixmap( "edit_paste" ), + tr( "Paste notes from clipboard " + "(Ctrl+V)" ), + this, SLOT( pasteNotes() ), + m_toolBar ); - toolTip::add( m_cutButton, tr( "Cut selected notes (Ctrl+X)" ) ); - toolTip::add( m_copyButton, tr( "Copy selected notes (Ctrl+C)" ) ); - toolTip::add( m_pasteButton, tr( "Paste notes from clipboard " - "(Ctrl+V)" ) ); #ifdef QT4 m_cutButton->setWhatsThis( #else @@ -427,9 +376,10 @@ pianoRoll::pianoRoll( void ) : + // setup zooming-stuff - m_zoomingComboBox = new QComboBox( this ); - m_zoomingComboBox->setGeometry( 580, 10, 60, 20 ); + m_zoomingComboBox = new QComboBox( m_toolBar ); + m_zoomingComboBox->setGeometry( 580, 4, 80, 24 ); for( int i = 0; i < 6; ++i ) { m_zoomingComboBox->insertItem( QString::number( 25 * @@ -441,6 +391,26 @@ pianoRoll::pianoRoll( void ) : this, SLOT( zoomingChanged( const QString & ) ) ); + + tb_layout->addSpacing( 5 ); + tb_layout->addWidget( m_playButton ); + tb_layout->addWidget( m_recordButton ); + tb_layout->addWidget( m_stopButton ); + tb_layout->addSpacing( 10 ); + tb_layout->addWidget( m_drawButton ); + tb_layout->addWidget( m_eraseButton ); + tb_layout->addWidget( m_selectButton ); + tb_layout->addWidget( m_moveButton ); + tb_layout->addSpacing( 10 ); + tb_layout->addWidget( m_cutButton ); + tb_layout->addWidget( m_copyButton ); + tb_layout->addWidget( m_pasteButton ); + tb_layout->addSpacing( 10 ); + m_timeLine->addToolButtons( m_toolBar ); + tb_layout->addSpacing( 10 ); + tb_layout->addWidget( m_zoomingComboBox ); + tb_layout->addStretch(); + // setup our actual window setWindowIcon( embed::getIconPixmap( "piano" ) ); resize( INITIAL_PIANOROLL_WIDTH, INITIAL_PIANOROLL_HEIGHT ); @@ -453,15 +423,6 @@ pianoRoll::pianoRoll( void ) : hide(); - // add time-line - m_timeLine = new timeLine( WHITE_KEY_WIDTH, 48, m_ppt, - songEditor::inst()->getPlayPos( - songEditor::PLAY_PATTERN ), - m_currentPosition, this ); - connect( this, SIGNAL( positionChanged( const midiTime & ) ), - m_timeLine, SLOT( updatePosition( const midiTime & ) ) ); - connect( m_timeLine, SIGNAL( positionChanged( const midiTime & ) ), - this, SLOT( updatePosition( const midiTime & ) ) ); } @@ -785,7 +746,7 @@ void pianoRoll::paintEvent( QPaintEvent * ) // draw artwork-stuff - p.drawPixmap( 0, 0, *s_artwork1 ); +/* p.drawPixmap( 0, 0, *s_artwork1 ); int artwork_x = s_artwork1->width(); @@ -793,10 +754,11 @@ void pianoRoll::paintEvent( QPaintEvent * ) { p.drawPixmap( artwork_x, 0, *s_artwork2 ); artwork_x += s_artwork2->width(); - } + }*/ - // set clipping area, because we may not draw on keyboard... + // 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 ); @@ -1027,6 +989,7 @@ void pianoRoll::resizeEvent( QResizeEvent * ) songEditor::inst()->getPlayPos( songEditor::PLAY_PATTERN ).m_timeLine->setFixedWidth( width() ); + m_toolBar->setFixedWidth( width() ); } @@ -1977,26 +1940,24 @@ void pianoRoll::play( void ) { songEditor::inst()->stop(); songEditor::inst()->playPattern( m_pattern ); - m_playButton->setInactiveGraphic( - embed::getIconPixmap( "pause" ) ); + m_playButton->setPixmap( embed::getIconPixmap( + "pause" ) ); } else { songEditor::inst()->pause(); - m_playButton->setInactiveGraphic( - embed::getIconPixmap( "play" ) ); + m_playButton->setPixmap( embed::getIconPixmap( + "play" ) ); } } else if( songEditor::inst()->paused() ) { songEditor::inst()->resumeFromPause(); - m_playButton->setInactiveGraphic( - embed::getIconPixmap( "pause" ) ); + m_playButton->setPixmap( embed::getIconPixmap( "pause" ) ); } else { - m_playButton->setInactiveGraphic( - embed::getIconPixmap( "pause" ) ); + m_playButton->setPixmap( embed::getIconPixmap( "pause" ) ); songEditor::inst()->playPattern( m_pattern ); } } @@ -2025,7 +1986,7 @@ void pianoRoll::record( void ) void pianoRoll::stop( void ) { songEditor::inst()->stop(); - m_playButton->setInactiveGraphic( embed::getIconPixmap( "play" ) ); + m_playButton->setPixmap( embed::getIconPixmap( "play" ) ); m_playButton->update(); m_recording = FALSE; m_scrollBack = TRUE; @@ -2071,56 +2032,47 @@ void pianoRoll::verScrolled( int _new_pos ) -void pianoRoll::drawButtonToggled( bool _on ) +void pianoRoll::drawButtonToggled( void ) { - if( _on ) - { - m_editMode = DRAW; - removeSelection(); - update(); - } -} - - - -void pianoRoll::eraseButtonToggled( bool _on ) -{ - if( _on ) - { - m_editMode = ERASE; - removeSelection(); - update(); - } + m_editMode = DRAW; + removeSelection(); + update(); } -void pianoRoll::selectButtonToggled( bool _on ) +void pianoRoll::eraseButtonToggled( void ) { - if( _on ) - { - m_editMode = SELECT; - removeSelection(); - update(); - } + m_editMode = ERASE; + removeSelection(); + update(); } -void pianoRoll::moveButtonToggled( bool _on ) + +void pianoRoll::selectButtonToggled( void ) { - if( _on ) - { - m_editMode = MOVE; - m_selNotesForMove.clear(); - getSelectedNotes( m_selNotesForMove ); - update(); - } + m_editMode = SELECT; + removeSelection(); + update(); } + +void pianoRoll::moveButtonToggled( void ) +{ + m_editMode = MOVE; + m_selNotesForMove.clear(); + getSelectedNotes( m_selNotesForMove ); + update(); +} + + + + void pianoRoll::selectAll( void ) { if( validPattern() == FALSE ) diff --git a/src/core/song_editor.cpp b/src/core/song_editor.cpp index 0b56de731..205be5ee6 100644 --- a/src/core/song_editor.cpp +++ b/src/core/song_editor.cpp @@ -44,11 +44,12 @@ #include #include #include -#include #include #include #include #include +#include +#include #else @@ -60,9 +61,10 @@ #include #include #include -#include #include #include +#include +#include #endif @@ -87,13 +89,13 @@ #include "midi_file.h" #include "lcd_spinbox.h" #include "tooltip.h" +#include "tool_button.h" #include "debug.h" extern QString file_to_load; -extern QString file_to_render; const int SCROLLBAR_SIZE = 16; @@ -114,7 +116,6 @@ songEditor::songEditor() : m_patternToPlay( NULL ), m_loopPattern( FALSE ), m_scrollBack( FALSE ), - m_epd( NULL ), m_shiftPressed( FALSE ), m_controlPressed( FALSE ) { @@ -147,7 +148,7 @@ songEditor::songEditor() : // create time-line timeLine * tl = new timeLine( TRACK_OP_WIDTH + - DEFAULT_SETTINGS_WIDGET_WIDTH, 0, + DEFAULT_SETTINGS_WIDGET_WIDTH, 32, pixelsPerTact(), m_playPos[PLAY_SONG], m_currentPosition, cw ); connect( this, SIGNAL( positionChanged( const midiTime & ) ), @@ -156,75 +157,41 @@ songEditor::songEditor() : connect( tl, SIGNAL( positionChanged( const midiTime & ) ), this, SLOT( updatePosition( const midiTime & ) ) ); + // create toolbar + m_toolBar = new QWidget( cw ); + m_toolBar->setFixedHeight( 32 ); + m_toolBar->move( 0, 0 ); + m_toolBar->setPaletteBackgroundPixmap( embed::getIconPixmap( + "toolbar_bg" ) ); + + QHBoxLayout * tb_layout = new QHBoxLayout( m_toolBar ); + + #ifdef QT4 containerWidget()->setParent( cw ); #else containerWidget()->reparent( cw, 0, QPoint( 0, 0 ) ); #endif - containerWidget()->move( 0, tl->height() ); + containerWidget()->move( 0, m_toolBar->height() + tl->height() ); - QToolBar * song_control = new QToolBar( tr( "Song control" ), this ); -#ifdef QT4 - addToolBar( Qt::TopToolBarArea, song_control ); -#else - addDockWindow( song_control, tr( "Song control" ), Qt::DockTop, - FALSE ); -#endif -/* song_control->setPaletteBackgroundPixmap( embed::getIconPixmap( - "toolbar_bg" ) ); - song_control->setErasePixmap( embed::getIconPixmap( "toolbar_bg" ) );*/ - -#ifdef QT4 - QAction * a; - - a = song_control->addAction( embed::getIconPixmap( "play" ), - tr( "Play song (Space)" ), - this, SLOT( play() ) ); - a->setToolTip( tr( "Play/pause song (Space)" ) ); - a->setWhatsThis( tr( "Click here, if you want to play your whole song. " - "Playing will be started at the song-position-" - "marker (green). You can also move it while " - "playing." ) ); -#else - m_playButton = new QToolButton( embed::getIconPixmap( "play" ), - tr( "Play song (Space)" ), - QString::null, this, SLOT( play() ), - song_control ); -#endif -#ifdef QT4 - a = song_control->addAction( embed::getIconPixmap( "stop" ), - tr( "Stop song (Space)" ), - this, SLOT( stop() ) ); - a->setToolTip( tr( "Stop song (Space)" ) ); - a->setWhatsThis( tr( "Click here, if you want to stop playing of your " - "song. The song-position-marker will be set to " - "the start of your song." ) ); -#else - m_stopButton = new QToolButton( embed::getIconPixmap( "stop" ), - tr( "Stop song (Space)" ), - QString::null, this, SLOT( stop() ), - song_control ); -#endif - - - song_control->addSeparator(); + QToolBar * main_tb = lmmsMainWin::inst()->mainToolBar(); // spacer-item - ( new QWidget( song_control ) )->setFixedSize( 10, 1 ); + ( new QWidget( main_tb ) )->setFixedSize( 10, 1 ); - QLabel * bpm_label = new QLabel( song_control ); + QLabel * bpm_label = new QLabel( main_tb ); bpm_label->setPixmap( embed::getIconPixmap( "clock" ) ); // spacer-item - ( new QWidget( song_control ) )->setFixedSize( 8, 1 ); + ( new QWidget( main_tb ) )->setFixedSize( 8, 1 ); - m_bpmSpinBox = new lcdSpinBox( MIN_BPM, MAX_BPM, 3, song_control ); + m_bpmSpinBox = new lcdSpinBox( MIN_BPM, MAX_BPM, 3, main_tb ); #ifdef QT4 - song_control->addWidget( m_bpmSpinBox ); - song_control->addWidget( bpm_label ); + main_tb->addWidget( m_bpmSpinBox ); + main_tb->addWidget( bpm_label ); #endif m_bpmSpinBox->setLabel( tr( "TEMPO/BPM" ) ); connect( m_bpmSpinBox, SIGNAL( valueChanged( int ) ), this, @@ -244,26 +211,26 @@ songEditor::songEditor() : "should be played within four minutes)." ) ); // spacer-item - ( new QWidget( song_control ) )->setFixedSize( 10, 1 ); + ( new QWidget( main_tb ) )->setFixedSize( 10, 1 ); - song_control->addSeparator(); + main_tb->addSeparator(); - QLabel * master_vol_lbl = new QLabel( song_control ); + QLabel * master_vol_lbl = new QLabel( main_tb ); master_vol_lbl->setPixmap( embed::getIconPixmap( "master_volume" ) ); #ifdef QT4 - m_masterVolumeSlider = new QSlider( Qt::Vertical, song_control ); + m_masterVolumeSlider = new QSlider( Qt::Vertical, main_tb ); m_masterVolumeSlider->setRange( 0, 200 ); m_masterVolumeSlider->setPageStep( 10 ); m_masterVolumeSlider->setValue( 100 ); m_masterVolumeSlider->setTickPosition( QSlider::TicksLeft ); - song_control->addWidget( master_vol_lbl ); - song_control->addWidget( m_masterVolumeSlider ); + main_tb->addWidget( master_vol_lbl ); + main_tb->addWidget( m_masterVolumeSlider ); #else m_masterVolumeSlider = new QSlider( 0, 200, 10, 100, Qt::Vertical, - song_control ); + main_tb ); m_masterVolumeSlider->setTickPosition( QSlider::Left ); #endif m_masterVolumeSlider->setFixedSize( 26, 48 ); @@ -281,22 +248,22 @@ songEditor::songEditor() : // spacer-item - ( new QWidget( song_control ) )->setFixedSize( 10, 1 ); + ( new QWidget( main_tb ) )->setFixedSize( 10, 1 ); - QLabel * master_pitch_lbl = new QLabel( song_control ); + QLabel * master_pitch_lbl = new QLabel( main_tb ); master_pitch_lbl->setPixmap( embed::getIconPixmap( "master_pitch" ) ); #ifdef QT4 - m_masterPitchSlider = new QSlider( Qt::Vertical, song_control ); + m_masterPitchSlider = new QSlider( Qt::Vertical, main_tb ); m_masterPitchSlider->setRange( -12, 12 ); m_masterPitchSlider->setPageStep( 1 ); m_masterPitchSlider->setValue( 0 ); m_masterPitchSlider->setTickPosition( QSlider::TicksLeft ); - song_control->addWidget( master_pitch_lbl ); - song_control->addWidget( m_masterPitchSlider ); + main_tb->addWidget( master_pitch_lbl ); + main_tb->addWidget( m_masterPitchSlider ); #else m_masterPitchSlider = new QSlider( -12, 12, 1, 0, Qt::Vertical, - song_control ); + main_tb); m_masterPitchSlider->setTickPosition( QSlider::Left ); #endif m_masterPitchSlider->setFixedSize( 26, 48 ); @@ -312,28 +279,117 @@ songEditor::songEditor() : SLOT( masterPitchReleased() ) ); // spacer-item - ( new QWidget( song_control ) )->setFixedSize( 5, 1 ); + ( new QWidget( main_tb ) )->setFixedSize( 5, 1 ); - song_control->addSeparator(); + main_tb->addSeparator(); // spacer-item - ( new QWidget( song_control ) )->setFixedSize( 5, 1 ); + ( new QWidget( main_tb ) )->setFixedSize( 5, 1 ); m_masterOutputGraph = new visualizationWidget( embed::getIconPixmap( - "output_graph" ), song_control ); + "output_graph" ), main_tb ); #ifdef QT4 - song_control->addWidget( m_masterOutputGraph ); + main_tb->addWidget( m_masterOutputGraph ); #endif - // live high-quality mode switching is somewhat experimental so we don't - // offer it... -/* QToolButton * hq = new QToolButton( - embed::getIconPixmap( "presetfile" ), + // spacer-item + ( new QWidget( main_tb ) )->setFixedSize( 5, 1 ); + + main_tb->addSeparator(); + + QToolButton * hq = new QToolButton( + embed::getIconPixmap( "hq_mode" ), tr( "High quality mode" ), QString::null, NULL, NULL, - song_control ); + main_tb ); hq->setToggleButton( TRUE ); connect( hq, SIGNAL( toggled( bool ) ), mixer::inst(), - SLOT( setHighQuality( bool ) ) );*/ + SLOT( setHighQuality( bool ) ) ); + + + + m_playButton = new toolButton( embed::getIconPixmap( "play" ), + tr( "Play song (Space)" ), + this, SLOT( play() ), m_toolBar ); + + m_stopButton = new toolButton( embed::getIconPixmap( "stop" ), + tr( "Stop song (Space)" ), + this, SLOT( stop() ), m_toolBar ); + + m_addBBTrackButton = new toolButton( embed::getIconPixmap( + "add_bb_track" ), + tr( "Add beat/bassline" ), + this, SLOT( addBBTrack() ), + m_toolBar ); + + m_addSampleTrackButton = new toolButton( embed::getIconPixmap( + "add_sample_track" ), + tr( "Add sample-track" ), + this, SLOT( addSampleTrack() ), + m_toolBar ); + + m_insertBarButton = new toolButton( embed::getIconPixmap( + "insert_bar" ), + tr( "Insert bar " + "(Shift+Insert)" ), + this, SLOT( insertBar() ), + m_toolBar ); + + m_removeBarButton = new toolButton( embed::getIconPixmap( + "remove_bar" ), + tr( "Remove bar (Shift+Delete)" ), + this, SLOT( removeBar() ), + m_toolBar ); +#ifdef QT4 +#else + QWhatsThis::add( m_playButton, tr( "Click here, if you want to play " + "your whole song. Playing will " + "be started at the " + "song-position-marker (green). " + "You can also move it while " + "playing." ) ); + QWhatsThis::add( m_stopButton, tr ( "Click here, if you want to stop " + "playing of your song. The " + "song-position-marker will be " + "set to the start of your song." + ) ); + QWhatsThis::add( m_insertBarButton, tr( "If you click here, a " + "bar will " + "be inserted at the " + "current bar." ) ); + QWhatsThis::add( m_removeBarButton, tr( "If you click here, the " + "current bar will be " + "removed." ) ); +#endif + + + // setup zooming-stuff + m_zoomingComboBox = new QComboBox( m_toolBar ); + m_zoomingComboBox->setGeometry( 580, 4, 80, 24 ); + for( int i = 0; i < 7; ++i ) + { + m_zoomingComboBox->insertItem( QString::number( 25 * + static_cast( powf( 2.0f, i ) ) ) + + "%" ); + } + m_zoomingComboBox->setCurrentText( "100%" ); + connect( m_zoomingComboBox, SIGNAL( activated( const QString & ) ), + this, SLOT( zoomingChanged( const QString & ) ) ); + + + tb_layout->addSpacing( 5 ); + tb_layout->addWidget( m_playButton ); + tb_layout->addWidget( m_stopButton ); + tb_layout->addSpacing( 10 ); + tb_layout->addWidget( m_addBBTrackButton ); + tb_layout->addWidget( m_addSampleTrackButton ); + tb_layout->addSpacing( 10 ); + tb_layout->addWidget( m_insertBarButton ); + tb_layout->addWidget( m_removeBarButton ); + tb_layout->addSpacing( 10 ); + tl->addToolButtons( m_toolBar ); + tb_layout->addSpacing( 10 ); + tb_layout->addWidget( m_zoomingComboBox ); + tb_layout->addStretch(); m_leftRightScroll = new QScrollBar( Qt::Horizontal, cw ); @@ -349,112 +405,6 @@ songEditor::songEditor() : SLOT( scrolled( int ) ) ); - QToolBar * edit_tb = new QToolBar( tr( "Edit" ), this ); -#ifdef QT4 - addToolBar( Qt::TopToolBarArea, edit_tb ); -#else - addDockWindow( edit_tb, tr( "Edit" ), Qt::DockTop, FALSE ); -#endif -/* edit_tb->setPaletteBackgroundPixmap( embed::getIconPixmap( - "toolbar_bg" ) ); - edit_tb->setErasePixmap( embed::getIconPixmap( "toolbar_bg" ) );*/ -#ifdef QT4 - a = edit_tb->addAction( embed::getIconPixmap( "add_bb_track" ), "", - this, SLOT( addBBTrack() ) ); - a->setToolTip( tr( "Add beat/bassline" ) ); -#else - m_addBBTrackButton = new QToolButton( embed::getIconPixmap( - "add_bb_track" ), "", "", - this, SLOT( addBBTrack() ), - edit_tb ); -#endif -#ifdef QT4 - a = edit_tb->addAction( embed::getIconPixmap( "add_sample_track" ), "", - this, SLOT( addSampleTrack() ) ); - a->setToolTip( tr( "Add sample-track" ) ); -#else - m_addSampleTrackButton = new QToolButton( embed::getIconPixmap( - "add_sample_track" ), "", "", - this, SLOT( addSampleTrack() ), - edit_tb ); - -#endif - - edit_tb->addSeparator(); - -#ifdef QT4 - a = edit_tb->addAction( embed::getIconPixmap( "se_insert_tact" ), "", - this, SLOT( insertTact() ) ); - a->setToolTip( tr( "Insert bar at current tact (Shift+Insert)" ) ); - a->setWhatsThis( tr( "If you click here, a tact will be inserted at " - "the current tact." ) ); -#else - m_insertTactButton = new QToolButton( embed::getIconPixmap( - "se_insert_tact" ), "", "", - this, SLOT( insertTact() ), - edit_tb ); -#endif -#ifdef QT4 - a = edit_tb->addAction( embed::getIconPixmap( "se_remove_tact" ), "", - this, SLOT( removeTact() ) ); - a->setToolTip( tr( "Remove bar at current tact (Shift+Delete)" ) ); - a->setWhatsThis( tr( "If you click here, the tact at the current tact " - "will be removed." ) ); -#else - m_removeTactButton = new QToolButton( embed::getIconPixmap( - "se_remove_tact" ), "", "", - this, SLOT( removeTact() ), - edit_tb ); -#endif - - // add tooltips and whats-this-texts to all buttons - - toolTip::add( m_playButton, tr( "Play/pause song (Space)" ) ); - toolTip::add( m_stopButton, tr( "Stop playing song (Space)" ) ); - toolTip::add( m_addBBTrackButton, tr( "Add beat/bassline" ) ); - toolTip::add( m_addSampleTrackButton, tr( "Add sample-track" ) ); - toolTip::add( m_insertTactButton, tr( "Insert tact at current tact " - "(Shift+Insert)" ) ); - toolTip::add( m_removeTactButton, tr( "Remove tact at current tact " - "(Shift+Delete)" ) ); -#ifdef QT4 -#else - QWhatsThis::add( m_playButton, tr( "Click here, if you want to play " - "your whole song. Playing will " - "be started at the " - "song-position-marker (green). " - "You can also move it while " - "playing." ) ); - QWhatsThis::add( m_stopButton, tr ( "Click here, if you want to stop " - "playing of your song. The " - "song-position-marker will be " - "set to the start of your song." - ) ); - QWhatsThis::add( m_insertTactButton, tr( "If you click here, a " - "tact will " - "be inserted at the " - "current tact." ) ); - QWhatsThis::add( m_removeTactButton, tr( "If you click here, the " - "tact at the " - "current tact will be " - "removed." ) ); -#endif - - edit_tb->addSeparator(); - - // setup zooming-stuff - m_zoomingComboBox = new QComboBox( edit_tb ); - m_zoomingComboBox->setGeometry( 580, 10, 60, 20 ); - for( int i = 0; i < 7; ++i ) - { - m_zoomingComboBox->insertItem( QString::number( 25 * - static_cast( powf( 2.0f, i ) ) ) + - "%" ); - } - m_zoomingComboBox->setCurrentText( "100%" ); - connect( m_zoomingComboBox, SIGNAL( activated( const QString & ) ), - this, SLOT( zoomingChanged( const QString & ) ) ); - show(); @@ -524,6 +474,7 @@ void songEditor::resizeEvent( QResizeEvent * _re ) m_playPos[PLAY_SONG].m_timeLine->setFixedWidth( centralWidget()->width() ); + m_toolBar->setFixedWidth( centralWidget()->width() ); } trackContainer::resizeEvent( _re ); } @@ -553,12 +504,12 @@ void songEditor::keyPressEvent( QKeyEvent * _ke ) if( _ke->modifiers() & Qt::ShiftModifier && _ke->key() == Qt::Key_Insert ) { - insertTact(); + insertBar(); } else if( _ke->modifiers() & Qt::ShiftModifier && _ke->key() == Qt::Key_Delete ) { - removeTact(); + removeBar(); } else if( _ke->key() == Qt::Key_Left ) { @@ -655,7 +606,7 @@ void songEditor::wheelEvent( QWheelEvent * _we ) void songEditor::masterVolumeChanged( int _new_val ) { - mixer::inst()->setMasterOutput( 2.0f - _new_val / 100.0f ); + mixer::inst()->setMasterGain( 2.0f - _new_val / 100.0f ); setModified(); } @@ -723,14 +674,6 @@ void songEditor::masterPitchReleased( void ) -void songEditor::toggleHQMode( void ) -{ - //mixer::inst()->setHighQuality (hq_btn->isChecked()); -} - - - - void songEditor::updatePosition( const midiTime & _t ) { if( ( m_playing && m_playMode == PLAY_SONG ) || m_scrollBack == TRUE ) @@ -953,7 +896,9 @@ void songEditor::processNextBuffer( void ) // check for looping-mode and act if neccessary timeLine * tl = m_playPos[m_playMode].m_timeLine; - if( tl != NULL && m_exporting == FALSE && tl->loopPointsEnabled() ) + if( tl != NULL && m_exporting == FALSE && tl->loopPointsEnabled() && + !( m_playMode == PLAY_PATTERN && + m_patternToPlay->freezing() == TRUE ) ) { if( m_playPos[m_playMode] < tl->loopBegin() || m_playPos[m_playMode] >= tl->loopEnd() ) @@ -1056,33 +1001,6 @@ void songEditor::processNextBuffer( void ) { m_playPos[m_playMode].m_timeLine->updatePosition(); } - - if( m_exporting == TRUE ) - { - tact tacts = lengthInTacts() + 1; - if( m_playPos[PLAY_SONG].getTact() >= tacts ) - { - // now pause the mixer - method - // exportProjectDialog::redrawProgressBar() which is - // called every 100 ms will find out that export - // is done and will act according to this - mixer::inst()->pause(); - } - else - { - m_epd->updateProgressBar( - ( m_playPos[PLAY_SONG].getTact() * 64 + - m_playPos[PLAY_SONG].getTact64th() ) * - 100 / ( tacts * 64 ) ); - } - } - - if( m_playMode == PLAY_PATTERN && m_loopPattern == FALSE && - m_patternToPlay->isFreezing() == TRUE && - m_playPos[PLAY_PATTERN] > m_patternToPlay->length() ) - { - m_patternToPlay->finishFreeze(); - } } @@ -1263,12 +1181,6 @@ void songEditor::stopExport( void ) { stop(); m_exporting = FALSE; - - // if we rendered file from cmd-line quit after export - if( file_to_render != "" ) - { - qApp->quit(); - } } @@ -1276,7 +1188,7 @@ void songEditor::stopExport( void ) -void songEditor::insertTact( void ) +void songEditor::insertBar( void ) { trackVector tv = tracks(); for( trackVector::iterator it = tv.begin(); it != tv.end(); ++it ) @@ -1289,7 +1201,7 @@ void songEditor::insertTact( void ) -void songEditor::removeTact( void ) +void songEditor::removeBar( void ) { trackVector tv = tracks(); for( trackVector::iterator it = tv.begin(); it != tv.end(); ++it ) @@ -1640,15 +1552,7 @@ void songEditor::exportProject( void ) if( m_fileName != "" ) { -#ifdef QT4 - base_filename = QFileInfo( m_fileName ).absolutePath() + "/" + - QFileInfo( m_fileName - ).completeBaseName(); -#else - base_filename = QFileInfo( m_fileName ).dirPath() + "/" + - QFileInfo( m_fileName ).baseName( - TRUE ); -#endif + base_filename = baseName( m_fileName ); } else { @@ -1709,12 +1613,9 @@ void songEditor::exportProject( void ) { return; } - - m_epd = new exportProjectDialog( export_file_name, + exportProjectDialog epd( export_file_name, lmmsMainWin::inst() ); - m_epd->exec(); - delete m_epd; - m_epd = NULL; + epd.exec(); } } diff --git a/src/core/timeline.cpp b/src/core/timeline.cpp index 09a1cc5b4..731a3397b 100644 --- a/src/core/timeline.cpp +++ b/src/core/timeline.cpp @@ -31,11 +31,13 @@ #include #include #include +#include #else #include #include +#include #endif @@ -44,18 +46,23 @@ #include "nstate_button.h" #include "embed.h" #include "templates.h" +#include "nstate_button.h" QPixmap * timeLine::s_timeLinePixmap = NULL; QPixmap * timeLine::s_posMarkerPixmap = NULL; QPixmap * timeLine::s_loopPointPixmap = NULL; +QPixmap * timeLine::s_loopPointDisabledPixmap = NULL; timeLine::timeLine( const int _xoff, const int _yoff, const float _ppt, songEditor::playPos & _pos, const midiTime & _begin, QWidget * _parent ) : QWidget( _parent ), + m_autoScroll( AUTOSCROLL_ENABLED ), + m_loopPoints( LOOP_POINTS_DISABLED ), + m_behaviourAtStop( BACK_TO_ZERO ), m_xOffset( _xoff ), m_posMarkerX( 0 ), m_ppt( _ppt ), @@ -84,41 +91,17 @@ timeLine::timeLine( const int _xoff, const int _yoff, const float _ppt, "loop_point" ) ); } + if( s_loopPointDisabledPixmap == NULL) + { + s_loopPointDisabledPixmap = new QPixmap( embed::getIconPixmap( + "loop_point_disabled" ) ); + } + move( 0, _yoff ); setFixedHeight( s_timeLinePixmap->height() ); m_xOffset -= s_posMarkerPixmap->width() / 2; - - m_autoScroll = new nStateButton( this ); - m_autoScroll->move( 3, 3 ); - m_autoScroll->setGeneralToolTip( tr( "Enable/disable " - "auto-scrolling" ) ); - m_autoScroll->addState( embed::getIconPixmap( "autoscroll_on" ) ); - m_autoScroll->addState( embed::getIconPixmap( "autoscroll_off" ) ); - - m_loopPoints = new nStateButton( this ); - m_loopPoints->move( 20, 3 ); - m_loopPoints->setGeneralToolTip( tr( "Enable/disable loop-points" ) ); - m_loopPoints->addState( embed::getIconPixmap( "loop_points_off" ) ); - m_loopPoints->addState( embed::getIconPixmap( "loop_points_on" ) ); - connect( m_loopPoints, SIGNAL( stateChanged( int ) ), this, - SLOT( toggleLoopPoints( int ) ) ); - - m_behaviourAtStop = new nStateButton( this ); - m_behaviourAtStop ->move( 37, 3 ); - m_behaviourAtStop ->addState( embed::getIconPixmap( "back_to_zero" ), - tr( "After stopping go back to begin" ) - ); - m_behaviourAtStop ->addState( embed::getIconPixmap( - "back_to_start" ), - tr( "After stopping go back to " - "position at which playing was " - "started" ) ); - m_behaviourAtStop ->addState( embed::getIconPixmap( - "keep_stop_position" ), - tr( "After stopping keep position" ) ); - #ifndef QT4 setBackgroundMode( Qt::NoBackground ); #endif @@ -139,18 +122,45 @@ timeLine::~timeLine() -timeLine::behaviourAtStopStates timeLine::behaviourAtStop( void ) const +void timeLine::addToolButtons( QWidget * _tool_bar ) { - return( static_cast( - m_behaviourAtStop->state() ) ); -} + nStateButton * m_autoScroll = new nStateButton( _tool_bar ); + m_autoScroll->setPaletteBackgroundColor( QColor( 224, 224, 224 ) ); + m_autoScroll->setGeneralToolTip( tr( "Enable/disable " + "auto-scrolling" ) ); + m_autoScroll->addState( embed::getIconPixmap( "autoscroll_on" ) ); + m_autoScroll->addState( embed::getIconPixmap( "autoscroll_off" ) ); + connect( m_autoScroll, SIGNAL( changedState( int ) ), this, + SLOT( toggleAutoScroll( int ) ) ); + nStateButton * m_loopPoints = new nStateButton( _tool_bar ); + m_loopPoints->setPaletteBackgroundColor( QColor( 224, 224, 224 ) ); + m_loopPoints->setGeneralToolTip( tr( "Enable/disable loop-points" ) ); + m_loopPoints->addState( embed::getIconPixmap( "loop_points_off" ) ); + m_loopPoints->addState( embed::getIconPixmap( "loop_points_on" ) ); + connect( m_loopPoints, SIGNAL( changedState( int ) ), this, + SLOT( toggleLoopPoints( int ) ) ); + nStateButton * m_behaviourAtStop = new nStateButton( _tool_bar ); + m_behaviourAtStop->setPaletteBackgroundColor( QColor( 224, 224, 224 ) ); + m_behaviourAtStop ->addState( embed::getIconPixmap( "back_to_zero" ), + tr( "After stopping go back to begin" ) + ); + m_behaviourAtStop ->addState( embed::getIconPixmap( + "back_to_start" ), + tr( "After stopping go back to " + "position at which playing was " + "started" ) ); + m_behaviourAtStop ->addState( embed::getIconPixmap( + "keep_stop_position" ), + tr( "After stopping keep position" ) ); + connect( m_behaviourAtStop, SIGNAL( changedState( int ) ), this, + SLOT( toggleBehaviourAtStop( int ) ) ); - -bool timeLine::loopPointsEnabled( void ) const -{ - return( m_loopPoints->state() == LOOP_POINTS_ENABLED ); + QBoxLayout * layout = dynamic_cast( _tool_bar->layout() ); + layout->addWidget( m_autoScroll ); + layout->addWidget( m_loopPoints ); + layout->addWidget( m_behaviourAtStop ); } @@ -170,7 +180,7 @@ void timeLine::updatePosition( const midiTime & ) #ifndef QT4 qApp->unlock(); #endif - if( m_autoScroll->state() == AUTOSCROLL_ENABLED ) + if( m_autoScroll == AUTOSCROLL_ENABLED ) { emit positionChanged( m_pos ); } @@ -180,14 +190,31 @@ void timeLine::updatePosition( const midiTime & ) +void timeLine::toggleAutoScroll( int _n ) +{ + m_autoScroll = static_cast( _n ); +} + + + + void timeLine::toggleLoopPoints( int _n ) { + m_loopPoints = static_cast( _n ); update(); } +void timeLine::toggleBehaviourAtStop( int _n ) +{ + m_behaviourAtStop = static_cast( _n ); +} + + + + void timeLine::paintEvent( QPaintEvent * ) { #ifdef QT4 @@ -205,13 +232,11 @@ void timeLine::paintEvent( QPaintEvent * ) p.setClipRect( m_xOffset, 0, width() - m_xOffset, height() ); p.setPen( QColor( 0, 0, 0 ) ); - if( m_loopPoints->state() == LOOP_POINTS_ENABLED ) - { - p.drawPixmap( markerX( m_loopPos[0] ), 7, - *s_loopPointPixmap ); - p.drawPixmap( markerX( m_loopPos[1] ), 7, - *s_loopPointPixmap ); - } + const QPixmap & lpoint = loopPointsEnabled() ? + *s_loopPointPixmap : + *s_loopPointDisabledPixmap; + p.drawPixmap( markerX( m_loopPos[0] ), 7, lpoint ); + p.drawPixmap( markerX( m_loopPos[1] ), 7, lpoint ); tact tact_num = m_begin.getTact(); @@ -225,7 +250,11 @@ void timeLine::paintEvent( QPaintEvent * ) if( ( tact_num - 1 ) % tMax( 1, static_cast( 64.0f / m_ppt ) ) == 0 ) { - p.drawText( x + static_cast( i * m_ppt ), 16, + p.setPen( QColor( 224, 224, 224 ) ); + p.drawText( x + static_cast( i * m_ppt ) + 1, 15, + QString::number( tact_num ) ); + p.setPen( QColor( 0, 0, 0 ) ); + p.drawText( x + static_cast( i * m_ppt ), 14, QString::number( tact_num ) ); } } @@ -249,10 +278,6 @@ void timeLine::mousePressEvent( QMouseEvent * _me ) } if( _me->button() == Qt::RightButton ) { - if( m_loopPoints->state() != LOOP_POINTS_ENABLED ) - { - return; - } if( _me->x() >= markerX( loopBegin() ) && _me->x() <= markerX( loopBegin() ) + s_loopPointPixmap->width() ) @@ -300,12 +325,12 @@ void timeLine::mouseMoveEvent( QMouseEvent * _me ) break; case MOVE_LOOP_BEGIN: - m_loopPos[0] = t; + m_loopPos[0] = t.getTact() * 64; update(); break; case MOVE_LOOP_END: - m_loopPos[1] = t; + m_loopPos[1] = t.getTact() * 64; update(); break; diff --git a/src/core/track.cpp b/src/core/track.cpp index 593d016de..93201dec5 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include #endif @@ -594,7 +596,7 @@ trackWidget::trackWidget( track * _track, QWidget * _parent ) : QPushButton * clntr_btn = new QPushButton( embed::getIconPixmap( - "pr_edit_copy", 12, 12 ), + "edit_copy", 12, 12 ), "", &m_trackOperationsWidget ); clntr_btn->setGeometry( 1, 1, TRACK_OP_BTN_WIDTH, TRACK_OP_BTN_HEIGHT ); diff --git a/src/midi/midi_alsa_raw.cpp b/src/midi/midi_alsa_raw.cpp index 5631a7072..e95653d1d 100644 --- a/src/midi/midi_alsa_raw.cpp +++ b/src/midi/midi_alsa_raw.cpp @@ -48,7 +48,7 @@ midiALSARaw::midiALSARaw( void ) : - midiRawClient(), + midiClientRaw(), QThread(), m_inputp( &m_input ), m_outputp( &m_output ), @@ -200,7 +200,7 @@ void midiALSARaw::run( void ) midiALSARaw::setupWidget::setupWidget( QWidget * _parent ) : - midiRawClient::setupWidget( midiALSARaw::name(), _parent ) + midiClientRaw::setupWidget( midiALSARaw::name(), _parent ) { m_device = new QLineEdit( midiALSARaw::probeDevice(), this ); m_device->setGeometry( 10, 20, 160, 20 ); diff --git a/src/midi/midi_alsa_seq.cpp b/src/midi/midi_alsa_seq.cpp index 5373da9bb..bd05cd2e5 100644 --- a/src/midi/midi_alsa_seq.cpp +++ b/src/midi/midi_alsa_seq.cpp @@ -74,7 +74,8 @@ midiALSASeq::midiALSASeq( void ) : m_queueID = snd_seq_alloc_queue( m_seqHandle ); snd_seq_queue_tempo_t * tempo; snd_seq_queue_tempo_alloca( &tempo ); - snd_seq_queue_tempo_set_tempo( tempo, 6000000 / songEditor::inst()->getBPM() ); + snd_seq_queue_tempo_set_tempo( tempo, 6000000 / + songEditor::inst()->getBPM() ); snd_seq_queue_tempo_set_ppq( tempo, 16 ); snd_seq_set_queue_tempo( m_seqHandle, m_queueID, tempo ); @@ -154,10 +155,10 @@ void midiALSASeq::processOutEvent( const midiEvent & _me, break; case NOTE_OFF: - snd_seq_ev_set_note( &ev, + snd_seq_ev_set_noteoff( &ev, _port->outputChannel(), _me.key() + NOTES_PER_OCTAVE, - _me.velocity(), 500 ); + _me.velocity() ); break; case KEY_PRESSURE: diff --git a/src/midi/midi_client.cpp b/src/midi/midi_client.cpp index 43a467e3b..d7075335e 100644 --- a/src/midi/midi_client.cpp +++ b/src/midi/midi_client.cpp @@ -35,10 +35,6 @@ #include "midi_port.h" #include "note.h" -/*#include "midi_alsa_raw.h" -#include "midi_alsa_seq.h" -#include "midi_oss.h" -#include "midi_dummy.h"*/ @@ -98,7 +94,7 @@ void midiClient::removePort( midiPort * _port ) -midiRawClient::midiRawClient() : +midiClientRaw::midiClientRaw() : midiClient() { } @@ -106,14 +102,14 @@ midiRawClient::midiRawClient() : -midiRawClient::~midiRawClient() +midiClientRaw::~midiClientRaw() { } -void midiRawClient::parseData( const Uint8 _c ) +void midiClientRaw::parseData( const Uint8 _c ) { /*********************************************************************/ /* 'Process' system real-time messages */ @@ -248,7 +244,7 @@ void midiRawClient::parseData( const Uint8 _c ) -void midiRawClient::processParsedEvent() +void midiClientRaw::processParsedEvent() { for( csize i = 0; i < m_midiPorts.size(); ++i ) { @@ -260,7 +256,7 @@ void midiRawClient::processParsedEvent() -void midiRawClient::processOutEvent( const midiEvent & _me, +void midiClientRaw::processOutEvent( const midiEvent & _me, const midiTime & , const midiPort * _port ) { @@ -293,7 +289,7 @@ void midiRawClient::processOutEvent( const midiEvent & _me, break; default: - printf( "midiRawClient: unhandled MIDI-event %d\n", + printf( "midiClientRaw: unhandled MIDI-event %d\n", (int) _me.m_type ); break; } @@ -331,7 +327,7 @@ const Uint8 REMAINS_80E0[] = // Returns the length of the MIDI message starting with _event. // Taken from Nagano Daisuke's USB-MIDI driver -Uint8 midiRawClient::eventLength( const Uint8 _event ) +Uint8 midiClientRaw::eventLength( const Uint8 _event ) { if ( _event < 0xF0 ) { diff --git a/src/midi/midi_oss.cpp b/src/midi/midi_oss.cpp index a1d96e128..74c2899ec 100644 --- a/src/midi/midi_oss.cpp +++ b/src/midi/midi_oss.cpp @@ -54,7 +54,7 @@ midiOSS::midiOSS( void ) : - midiRawClient(), + midiClientRaw(), QThread(), m_midiDev( probeDevice() ), m_quit( FALSE ) @@ -143,7 +143,7 @@ void midiOSS::run( void ) midiOSS::setupWidget::setupWidget( QWidget * _parent ) : - midiRawClient::setupWidget( midiOSS::name(), _parent ) + midiClientRaw::setupWidget( midiOSS::name(), _parent ) { m_device = new QLineEdit( midiOSS::probeDevice(), this ); m_device->setGeometry( 10, 20, 160, 20 ); diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index af86b616f..38a77b83a 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -42,7 +41,6 @@ #include #include #include -#include #include #include @@ -79,9 +77,8 @@ pattern::pattern ( channelTrack * _channel_track ) : m_name( _channel_track->name() ), m_frozenPatternMutex(), m_frozenPattern( NULL ), - m_freezeRecorder( NULL ), - m_freezeStatusDialog( NULL ), - m_freezeStatusUpdateTimer( NULL ) + m_freezing( FALSE ), + m_freezeAborted( FALSE ) { initPixmaps(); @@ -118,7 +115,8 @@ pattern::pattern( const pattern & _pat_to_copy ) : m_patternType( _pat_to_copy.m_patternType ), m_name( "" ), m_frozenPatternMutex(), - m_frozenPattern( NULL ) + m_frozenPattern( NULL ), + m_freezeAborted( FALSE ) { initPixmaps(); @@ -573,7 +571,8 @@ void pattern::freeze( void ) ( 0, tr( "Channel muted" ), tr( "The channel this pattern " "belongs to is " - "currently muted, so " + "currently muted " + "therefore " "freezing makes no " "sense! Do you still " "want to continue?" ), @@ -594,15 +593,17 @@ void pattern::freeze( void ) unfreeze(); } - mixer::inst()->pause(); - + // create and install audio-sample-recorder bool b; - m_freezeRecorder = new audioSampleRecorder( - mixer::inst()->sampleRate(), - DEFAULT_CHANNELS, b ); - mixer::inst()->setAudioDevice( m_freezeRecorder, + // we cannot create local copy, because at a later stage + // mixer::restoreAudioDevice(...) deletes old audio-dev and thus + // audioSampleRecorder would be destroyed two times... + audioSampleRecorder * freeze_recorder = new audioSampleRecorder( + mixer::inst()->sampleRate(), DEFAULT_CHANNELS, b ); + mixer::inst()->setAudioDevice( freeze_recorder, mixer::inst()->highQuality() ); + // prepare stuff for playing correct things later songEditor::inst()->playPattern( this, FALSE ); songEditor::playPos & ppp = songEditor::inst()->getPlayPos( songEditor::PLAY_PATTERN ); @@ -610,19 +611,41 @@ void pattern::freeze( void ) ppp.setTact64th( 0 ); ppp.setCurrentFrame( 0 ); ppp.m_timeLineUpdate = FALSE; - m_freezeStatusDialog = new patternFreezeStatusDialog; - connect( m_freezeStatusDialog, SIGNAL( aborted() ), this, - SLOT( abortFreeze() ) ); - m_freezeStatusUpdateTimer = new QTimer( this ); - connect( m_freezeStatusUpdateTimer, SIGNAL( timeout() ), this, - SLOT( updateFreezeStatusDialog() ) ); + // create status-dialog + patternFreezeStatusDialog status_dlg; + status_dlg.show(); + connect( &status_dlg, SIGNAL( aborted() ), + this, SLOT( abortFreeze() ) ); - m_freezeStatusUpdateTimer->start( 50 ); + m_freezeAborted = FALSE; + m_freezing = TRUE; - m_freezeStatusDialog->show(); + // now render everything + while( ppp < length() && m_freezeAborted == FALSE ) + { + freeze_recorder->processNextBuffer(); + status_dlg.setProgress( ppp * 100 / length() ); + qApp->processEvents(); + } - mixer::inst()->play(); + m_freezing = FALSE; + + // reset song-editor settings + songEditor::inst()->stop(); + songEditor::inst()->getPlayPos( songEditor::PLAY_PATTERN + ).m_timeLineUpdate = TRUE; + + // create final sample-buffer if freezing was successful + if( m_freezeAborted == FALSE ) + { + m_frozenPatternMutex.lock(); + freeze_recorder->createSampleBuffer( &m_frozenPattern ); + m_frozenPatternMutex.unlock(); + } + + // restore original audio-device + mixer::inst()->restoreAudioDevice(); } @@ -642,62 +665,9 @@ void pattern::unfreeze( void ) -void pattern::updateFreezeStatusDialog( void ) -{ - m_freezeStatusDialog->setProgress( songEditor::inst()->getPlayPos( - songEditor::PLAY_PATTERN ) * - 100 / length() ); - m_frozenPatternMutex.lock(); - - // finishFreeze called? - if( m_freezeRecorder == NULL ) - { - // then we're done and destroy the timer and the dialog - delete m_freezeStatusUpdateTimer; - delete m_freezeStatusDialog; - m_freezeStatusUpdateTimer = NULL; - m_freezeStatusDialog = NULL; - } - - m_frozenPatternMutex.unlock(); -} - - - - -void pattern::finishFreeze( void ) -{ - songEditor::inst()->stop(); - - m_frozenPatternMutex.lock(); - - m_freezeRecorder->createSampleBuffer( &m_frozenPattern ); - - mixer::inst()->restoreAudioDevice(); - m_freezeRecorder = NULL; - - songEditor::inst()->getPlayPos( songEditor::PLAY_PATTERN - ).m_timeLineUpdate = TRUE; - - m_frozenPatternMutex.unlock(); -} - - - - void pattern::abortFreeze( void ) { - songEditor::inst()->stop(); - - m_frozenPatternMutex.lock(); - - mixer::inst()->restoreAudioDevice(); - m_freezeRecorder = NULL; - - songEditor::inst()->getPlayPos( songEditor::PLAY_PATTERN - ).m_timeLineUpdate = TRUE; - - m_frozenPatternMutex.unlock(); + m_freezeAborted = TRUE; } @@ -788,7 +758,7 @@ void pattern::removeNote( const note * _note_to_del ) noteVector::iterator it = m_notes.begin(); while( it != m_notes.end() ) { - if( ( *it ) == _note_to_del ) + if( *it == _note_to_del ) { delete *it; m_notes.erase( it ); @@ -961,7 +931,8 @@ void pattern::loadSettings( const QDomElement & _this ) -patternFreezeStatusDialog::patternFreezeStatusDialog( void ) +patternFreezeStatusDialog::patternFreezeStatusDialog( void ) : + QDialog() { setWindowTitle( tr( "Freezing pattern..." ) ); #if QT_VERSION >= 0x030200 @@ -980,6 +951,7 @@ patternFreezeStatusDialog::patternFreezeStatusDialog( void ) m_cancelBtn = new QPushButton( embed::getIconPixmap( "cancel" ), tr( "Cancel" ), this ); m_cancelBtn->setGeometry( 50, 38, 120, 28 ); + m_cancelBtn->show(); connect( m_cancelBtn, SIGNAL( clicked() ), this, SLOT( cancelBtnClicked() ) ); } diff --git a/src/widgets/nstate_button.cpp b/src/widgets/nstate_button.cpp index 6d3108851..1a4d50701 100644 --- a/src/widgets/nstate_button.cpp +++ b/src/widgets/nstate_button.cpp @@ -44,13 +44,10 @@ nStateButton::nStateButton( QWidget * _parent ) : - QWidget( _parent ), + QPushButton( _parent ), m_generalToolTip( "" ), m_curState( -1 ) { -#ifndef QT4 - setBackgroundMode( Qt::NoBackground ); -#endif } @@ -75,7 +72,7 @@ void nStateButton::addState( const QPixmap & _pm, const QString & _tooltip ) if( m_states.size() == 1 ) { // then resize ourself - resize( _pm.width(), _pm.height() ); + setFixedSize( _pm.width() + 6, _pm.height() + 6 ); // and set state to first pixmap changeState( 0 ); } @@ -96,15 +93,17 @@ void nStateButton::changeState( int _n ) m_generalToolTip; toolTip::add( this, _tooltip ); - emit stateChanged( m_curState ); + setPixmap( *m_states[m_curState].first ); - update(); + emit changedState( m_curState ); + +/* update();*/ } } - +/* void nStateButton::paintEvent( QPaintEvent * ) { #ifdef QT4 @@ -125,7 +124,7 @@ void nStateButton::paintEvent( QPaintEvent * ) bitBlt( this, rect().topLeft(), &draw_pm ); #endif } - +*/ @@ -135,6 +134,7 @@ void nStateButton::mousePressEvent( QMouseEvent * _me ) { changeState( ( ++m_curState ) % m_states.size() ); } + QPushButton::mousePressEvent( _me ); } diff --git a/src/widgets/tab_widget.cpp b/src/widgets/tab_widget.cpp index 1cb14b024..d25625c56 100644 --- a/src/widgets/tab_widget.cpp +++ b/src/widgets/tab_widget.cpp @@ -209,7 +209,7 @@ void tabWidget::paintEvent( QPaintEvent * _pe ) void tabWidget::wheelEvent( QWheelEvent * _we ) { _we->accept(); - int dir = ( _we->delta() > 0 ) ? 1 : -1; + int dir = ( _we->delta() < 0 ) ? 1 : -1; int tab = m_activeTab; while( tab > -1 && static_cast( tab ) < m_widgets.count() ) { diff --git a/src/widgets/visualization_widget.cpp b/src/widgets/visualization_widget.cpp index 5fe63165f..910806ace 100644 --- a/src/widgets/visualization_widget.cpp +++ b/src/widgets/visualization_widget.cpp @@ -129,7 +129,7 @@ void visualizationWidget::paintEvent( QPaintEvent * ) if( m_enabled ) { - float master_output = mixer::inst()->masterOutput(); + float master_output = mixer::inst()->masterGain(); Uint16 w = width()-4; float half_h = -( height() - 6 ) / 3.0 * master_output - 1; Uint16 x_base = 2;