bug fixes, GUI-improvements and more

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@31 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2005-12-12 14:25:32 +00:00
parent f67bf64acb
commit d5a5f3abca
37 changed files with 886 additions and 335 deletions

View File

@@ -1,3 +1,82 @@
2005-12-11 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* src/core/lmms_main_win.cpp:
* src/lib/mmp.cpp:
- default file-extension is now "mmp" (MultiMedia Project) instead of
"xml" for being able to associate mmp-files with LMMS in
file-managers etc. - futhermore LMMS-file-browser is much faster now
because it does not have to examine each file
- file-extension for song-templates is now "mpt" (MultiMedia Project
Template)
* include/cpuload_widget.h:
* src/widgets/cpuload_widget.cpp:
added cool CPU-load-widget displaying LMMS's current CPU-usage
* src/core/note_play_handle.cpp:
always check validity of sub-notes as they might not be known to mixer
and therefore not invalidated in certain situations which made LMMS
crashing (e.g. when deleting a channel-track which was current playing
some arpeggio-notes)
* include/pattern.h:
* src/tracks/pattern.cpp:
start separate thread for freezing pattern as this doesn't block the
GUI-thread and user is now able to cancel pattern-freezing (which was
not possible after last rewrite a few days ago)
* include/timeline.h:
* src/core/timeline.cpp:
use timer for periodically screen-updates - locking QApplication-mutex
isn't neccessary anymore which makes LMMS not to hang when creating
new song while playing etc.
* src/core/piano_roll.cpp:
when settings time-line-position, call setTact( 0 ) and
setTact64th( 0 )-members instead of pos() = 0 (the latter one leads
to crashes)
* plugins/audio_file_processor/audio_file_processor.cpp:
update start- and end-frames of sample-buffer when loading settings
2005-12-10 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* include/lmms_main_win.h:
* include/song_editor.h:
* src/core/lmms_main_win.cpp:
* src/core/song_editor.cpp:
* resources/toolbar_bg.png:
* resources/main_toolbar_bg.png:
heavy improvements on toolbars
* include/nstate_button.h:
* src/widgets/nstate_button.cpp:
base-class is now toolButton instead of QPushButton
* include/tool_button.h:
* src/widgets/tool_button.cpp:
- moved implemenation of toolButton into cpp-file
- added highlighting during mouse-over
- do not connect clicked()-signal if receiver and/or slot are NULL
2005-12-09 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* include/channel_track.h:
* src/core/midi_tab_widget.cpp:
* src/core/preset_preview_play_handle.cpp:
added support for saving and restoring MIDI-connections of a channel
in ordinary channel-preset-data
* include/channel_track.h:
* include/midi_tab_widget.h:
* src/core/midi_tab_widget.cpp:
* src/tracks/channel_track.cpp:
dropped support for switchable MIDI-event-routing as it is done per
default and actually makes no sense...
* src/midi/midi_port.cpp:
do not process MIDI-out-event if channel = -1
2005-12-08 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* src/core/midi_tab_widget.cpp:

View File

@@ -48,6 +48,7 @@ lmms_MOC = \
./bb_track.moc \
./channel_track.moc \
./config_mgr.moc \
./cpuload_widget.moc \
./envelope_and_lfo_widget.moc \
./envelope_tab_widget.moc \
./export_project_dialog.moc \
@@ -156,6 +157,7 @@ lmms_SOURCES = \
$(srcdir)/src/tracks/channel_track.cpp \
$(srcdir)/src/tracks/pattern.cpp \
$(srcdir)/src/tracks/sample_track.cpp \
$(srcdir)/src/widgets/cpuload_widget.cpp \
$(srcdir)/src/widgets/group_box.cpp \
$(srcdir)/src/widgets/kmultitabbar.cpp \
$(srcdir)/src/widgets/knob.cpp \
@@ -171,6 +173,7 @@ lmms_SOURCES = \
$(srcdir)/src/widgets/tab_widget.cpp \
$(srcdir)/src/widgets/text_float.cpp \
$(srcdir)/src/widgets/tempo_sync_knob.cpp \
$(srcdir)/src/widgets/tool_button.cpp \
$(srcdir)/src/widgets/tooltip.cpp \
$(srcdir)/src/widgets/visualization_widget.cpp \
$(srcdir)/include/pch.h \
@@ -272,6 +275,7 @@ lmms_SOURCES = \
$(srcdir)/include/audio_port.h \
$(srcdir)/include/qxembed.h \
$(srcdir)/include/tool_button.h \
$(srcdir)/include/cpuload_widget.h \
$(srcdir)/include/midi_alsa_seq.h

2
TODO
View File

@@ -1,9 +1,7 @@
to be done as soon as possible:
- do not allow to connect output-port of channel to own input-port!
- save connections in midi-tab-widget
- add note-len- and note-alignment-selectbox to piano-roll
- make it possible in bb-editor to add single beats to beat-patterns
- fix audio/midi-settings stuff/translation
- tooltips for controls in MIDI-tab
- sample-track: sane bg and wave-color

View File

@@ -2,8 +2,8 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.50)
AC_INIT(lmms, 0.1.1-cvs20051208, tobydox/at/users.sourceforge.net)
AM_INIT_AUTOMAKE(lmms, 0.1.1-cvs20051208)
AC_INIT(lmms, 0.1.1-cvs20051211, tobydox/at/users.sourceforge.net)
AM_INIT_AUTOMAKE(lmms, 0.1.1-cvs20051211)
AM_CONFIG_HEADER(config.h)
@@ -383,7 +383,6 @@ AC_CONFIG_FILES([Makefile
plugins/vestige/Makefile
presets/Makefile
presets/AudioFileProcessor/Makefile
presets/MIDI-Out/Makefile
presets/PluckedStringSynth/Makefile
presets/TripleOscillator/Makefile
presets/VeSTige/Makefile

79
include/cpuload_widget.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* cpuload_widget.h - widget for displaying CPU-load (partly based on
* Hydrogen's CPU-load-widget)
*
* Copyright (c) 2005 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* 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 _CPULOAD_WIDGET_H
#define _CPULOAD_WIDGET_H
#include "qt3support.h"
#ifdef QT4
#include <QWidget>
#include <QPixmap>
#include <QTimer>
#else
#include <qwidget.h>
#include <qpixmap.h>
#include <qtimer.h>
#endif
#include "types.h"
class cpuloadWidget : public QWidget
{
Q_OBJECT
public:
cpuloadWidget( QWidget * _parent );
~cpuloadWidget();
protected:
void paintEvent( QPaintEvent * _ev );
protected slots:
void updateCpuLoad();
private:
Uint8 m_currentLoad;
QPixmap m_temp;
QPixmap m_background;
QPixmap m_leds;
bool m_changed;
QTimer m_updateTimer;
} ;
#endif

View File

@@ -92,7 +92,7 @@ private:
lcdSpinBox * m_outputChannelSpinBox;
ledCheckBox * m_receiveCheckBox;
ledCheckBox * m_sendCheckBox;
ledCheckBox * m_routeCheckBox;
QMenu * m_readablePorts;
QMenu * m_writeablePorts;

View File

@@ -125,6 +125,10 @@ public:
return( m_framesPerAudioBuffer );
}
inline Uint8 cpuLoad( void ) const
{
return( m_cpuLoad );
}
inline bool highQuality( void ) const
{
@@ -295,16 +299,13 @@ private:
surroundSampleFrame * m_curBuf;
surroundSampleFrame * m_nextBuf;
/* bool m_discardCurBuf;*/
Uint8 m_cpuLoad;
playHandleVector m_playHandles;
playHandleVector m_playHandlesToRemove;
Uint8 m_qualityLevel;
volatile float m_masterGain;
/* volatile bool m_quit;*/
float m_masterGain;
audioDevice * m_audioDev;
@@ -317,7 +318,6 @@ private:
QMutex m_mixMutex;
/* QMutex m_devMutex;*/
friend class lmmsMainWin;

View File

@@ -49,6 +49,7 @@ public:
{
UNKNOWN,
SONG_PROJECT,
SONG_PROJECT_TEMPLATE,
CHANNEL_SETTINGS,
EFFECT_SETTINGS,
VIDEO_PROJECT, // will come later...

View File

@@ -34,22 +34,21 @@
#ifdef QT4
#include <QPushButton>
#include <QPixmap>
#include <QVector>
#include <QPair>
#else
#include <qpushbutton.h>
#include <qpixmap.h>
#include <qvaluevector.h>
#include <qpair.h>
#endif
#include "tool_button.h"
class nStateButton : public QPushButton
class nStateButton : public toolButton
{
Q_OBJECT
public:
@@ -77,7 +76,6 @@ signals:
protected:
/* virtual void paintEvent( QPaintEvent * _pe );*/
virtual void mousePressEvent( QMouseEvent * _me );

View File

@@ -35,6 +35,7 @@
#include <QWidget>
#include <QMutex>
#include <QDialog>
#include <QThread>
#else
@@ -42,6 +43,7 @@
#include <qwidget.h>
#include <qmutex.h>
#include <qdialog.h>
#include <qthread.h>
#endif
@@ -51,16 +53,18 @@
#include "mixer.h"
class channelTrack;
class sampleBuffer;
class QProgressBar;
class QPushButton;
class QPixmap;
class channelTrack;
class patternFreezeThread;
class sampleBuffer;
const int MAX_BEATS_PER_TACT = 16;
const int MAIN_BEATS_PER_TACT = 4;
const int DEFAULT_STEPS_PER_TACT = 16;
const int BEATS_PER_TACT = 4;
class pattern : public trackContentObject
@@ -76,6 +80,9 @@ public:
pattern( const pattern & _pat_to_copy ) FASTCALL;
virtual ~pattern();
void init( void );
virtual void FASTCALL movePosition( const midiTime & _pos );
@@ -130,6 +137,8 @@ public:
return( m_frozenPattern != NULL );
}
// if channel-track recognizes that this pattern is frozen, it calls
// this instead of playing all the notes
void FASTCALL playFrozenData( sampleFrame * _ab, Uint32 _start_frame,
Uint32 _frames );
@@ -150,6 +159,7 @@ public:
protected slots:
void openInPianoRoll( bool _c );
void openInPianoRoll( void );
void clear( void );
void resetName( void );
void changeName( void );
@@ -157,6 +167,9 @@ protected slots:
void unfreeze( void );
void abortFreeze( void );
void addSteps( int _n );
void removeSteps( int _n );
protected:
void paintEvent( QPaintEvent * _pe );
@@ -174,19 +187,30 @@ private:
static QPixmap * s_stepBtnOffLight;
static QPixmap * s_frozen;
static void initPixmaps( void );
// general stuff
channelTrack * m_channelTrack;
patternTypes m_patternType;
QString m_name;
noteVector m_notes;
// data-stuff
noteVector m_notes;
int m_steps;
// pattern freezing
QMutex m_frozenPatternMutex;
sampleBuffer * m_frozenPattern;
bool m_freezing;
volatile bool m_freezeAborted;
// as in Qt4 QThread is inherits from QObject and our base
// trackContentObject is a QWidget (=QObject), we cannot inherit from
// QThread. That's why we have to put pattern-freezing into separate
// thread-class -> patternFreezeThread
friend class patternFreezeThread;
} ;
@@ -196,7 +220,7 @@ class patternFreezeStatusDialog : public QDialog
{
Q_OBJECT
public:
patternFreezeStatusDialog();
patternFreezeStatusDialog( QThread * _thread );
~patternFreezeStatusDialog();
void FASTCALL setProgress( int _p );
@@ -208,12 +232,17 @@ protected:
protected slots:
void cancelBtnClicked( void );
void updateProgress( void );
private:
QProgressBar * m_progressBar;
QPushButton * m_cancelBtn;
QThread * m_freezeThread;
int m_progress;
signals:
void aborted( void );
@@ -221,4 +250,25 @@ signals:
} ;
class patternFreezeThread : public QThread
{
public:
patternFreezeThread( pattern * _pattern );
virtual ~patternFreezeThread();
protected:
virtual void run( void );
private:
pattern * m_pattern;
patternFreezeStatusDialog * m_statusDlg;
} ;
#endif

View File

@@ -56,7 +56,6 @@ class pattern;
class projectNotes;
class timeLine;
class toolButton;
class visualizationWidget;
const int MIN_BPM = 10;
@@ -283,8 +282,6 @@ private:
QSlider * m_masterVolumeSlider;
QSlider * m_masterPitchSlider;
visualizationWidget * m_masterOutputGraph;
toolButton * m_addBBTrackButton;
toolButton * m_addSampleTrackButton;

View File

@@ -119,6 +119,7 @@ public slots:
void toggleAutoScroll( int _n );
void toggleLoopPoints( int _n );
void toggleBehaviourAtStop( int _n );
void checkForUpdatedPosition( void );
protected:
@@ -144,6 +145,8 @@ private:
loopPointStates m_loopPoints;
behaviourAtStopStates m_behaviourAtStop;
bool m_changedPosition;
int m_xOffset;
int m_posMarkerX;
float m_ppt;

View File

@@ -26,44 +26,60 @@
#ifndef _TOOL_BUTTON_H
#define _TOOL_BUTTON_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "qt3support.h"
#ifdef QT4
#include <QPushButton>
#include <QToolButton>
#include <QColor>
#else
#include <qpushbutton.h>
#include <qtoolbutton.h>
#include <qcolor.h>
#endif
#include "tooltip.h"
class toolButton : public QPushButton
class toolButton : public QToolButton
{
public:
toolButton( const QPixmap & _pixmap, const QString & _tooltip,
QObject * _receiver, const char * _slot,
QWidget * _parent ) :
QPushButton( _parent )
QWidget * _parent );
inline toolButton( QWidget * _parent ) :
QToolButton( _parent ),
m_colorStandard( s_stdColor ),
m_colorHighlighted( s_hlColor )
{
connect( this, SIGNAL( clicked() ), _receiver, _slot );
toolTip::add( this, _tooltip );
setPaletteBackgroundColor( QColor( 224, 224, 224 ) );
setFixedSize( 30, 30 );
setPixmap( _pixmap );
}
~toolButton()
~toolButton();
inline void setStandardColor( const QColor & _color )
{
m_colorStandard = _color;
}
inline void setHighlightedColor( const QColor & _color )
{
m_colorHighlighted = _color;
}
protected:
virtual void enterEvent( QEvent * _ev );
virtual void leaveEvent( QEvent * _ev );
private:
static const QColor s_stdColor;
static const QColor s_hlColor;
QColor m_colorStandard;
QColor m_colorHighlighted;
} ;
#endif

View File

@@ -2,6 +2,6 @@ if VST_SUPPORT
VESTIGE_SUBDIR=vestige
endif
SUBDIRS = audio_file_processor midi_out plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR)
SUBDIRS = audio_file_processor plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR)

View File

@@ -487,7 +487,7 @@ void audioFileProcessor::sampleUpdated( void )
{
m_graph = QPixmap( 245, 75 );
copyBlt( &m_graph, 0, 0, s_artwork, 2, 172, m_graph.width(),
m_graph.height() );
m_graph.height() );
QPainter p( &m_graph );
m_sampleBuffer.drawWaves( p, QRect( 2, 2, m_graph.width() - 4,
m_graph.height() - 4 ),
@@ -541,20 +541,20 @@ void audioFileProcessor::ampKnobChanged( float _val )
void audioFileProcessor::setStartAndEndKnob( float _s, float _e )
{
// because the signal-handlers of valuechanges of start- and end-knob
/* // because the signal-handlers of valuechanges of start- and end-knob
// do range checking, depending on value of the other knob, we have to
// disconnect the signal-handlers, set then the values, connect again
// and then let the changes take effect...
m_startKnob->disconnect();
m_endKnob->disconnect();
m_endKnob->disconnect();*/
m_startKnob->setValue( _s );
m_endKnob->setValue( _e );
connect( m_startKnob, SIGNAL( valueChanged( float ) ), this,
/* connect( m_startKnob, SIGNAL( valueChanged( float ) ), this,
SLOT( startKnobChanged( float ) ) );
connect( m_endKnob, SIGNAL( valueChanged( float ) ), this,
SLOT( endKnobChanged( float ) ) );
m_startKnob->setValue( _s );
m_endKnob->setValue( _e );
SLOT( endKnobChanged( float ) ) );*/
startKnobChanged( _s );
endKnobChanged( _e );
}

BIN
resources/cpuload_bg.png Normal file

Binary file not shown.

BIN
resources/cpuload_leds.png Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -193,7 +193,7 @@ void audioALSA::stopProcessing( void )
if( running() )
{
m_quit = TRUE;
wait( 500 );
wait( 1000 );
terminate();
}
}

View File

@@ -296,7 +296,7 @@ void audioOSS::stopProcessing( void )
if( running() )
{
m_quit = TRUE;
wait( 500 );
wait( 1000 );
terminate();
}
}

View File

@@ -1,5 +1,6 @@
/*
* file_browser.cpp - implementation of the project-, preset- and sample-file-browser
* file_browser.cpp - implementation of the project-, preset- and
* sample-file-browser
*
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -718,7 +719,7 @@ void fileItem::determineFileType( void )
#else
QString ext = QFileInfo( fullName() ).extension( FALSE ).toLower();
#endif
if( ext == "mmp" )
if( ext == "mmp" || ext == "mpt" )
{
m_type = SONG_FILE;
}

View File

@@ -67,7 +67,7 @@ midiTabWidget::midiTabWidget( channelTrack * _channel_track,
{
m_setupTabWidget = new tabWidget( tr( "MIDI-SETUP FOR THIS CHANNEL" ),
this );
m_setupTabWidget->setGeometry( 4, 5, 238, 180 );
m_setupTabWidget->setGeometry( 4, 5, 238, 160 );
m_inputChannelSpinBox = new lcdSpinBox( 0, MIDI_CHANNEL_COUNT, 3,
@@ -107,14 +107,6 @@ midiTabWidget::midiTabWidget( channelTrack * _channel_track,
m_outputChannelSpinBox, SLOT( setEnabled( bool ) ) );
m_routeCheckBox = new ledCheckBox( tr( "SEND RECEIVED MIDI-EVENTS" ),
m_setupTabWidget );
m_routeCheckBox->setChecked(
m_channelTrack->midiEventRoutingEnabled() );
m_routeCheckBox->move( 10, 150 );
connect( m_sendCheckBox, SIGNAL( toggled( bool ) ),
m_channelTrack, SLOT( toggleMidiEventRouting( bool ) ) );
midiPort::modes m = m_midiPort->mode();
m_receiveCheckBox->setChecked( m == midiPort::INPUT ||
m == midiPort::DUPLEX );
@@ -183,8 +175,44 @@ void midiTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _parent )
m_receiveCheckBox->isChecked() ) );
mw_de.setAttribute( "send", QString::number(
m_sendCheckBox->isChecked() ) );
mw_de.setAttribute( "route", QString::number(
m_routeCheckBox->isChecked() ) );
if( m_readablePorts != NULL && m_receiveCheckBox->isChecked() == TRUE )
{
QString rp;
for( csize i = 0; i < m_readablePorts->count(); ++i )
{
int id = m_readablePorts->idAt( i );
if( m_readablePorts->isItemChecked( id ) )
{
rp += m_readablePorts->text( id ) + ",";
}
}
// cut off comma
if( rp.length() > 0 )
{
rp.truncate( rp.length() - 1 );
}
mw_de.setAttribute( "inports", rp );
}
if( m_writeablePorts != NULL && m_sendCheckBox->isChecked() == TRUE )
{
QString wp;
for( csize i = 0; i < m_writeablePorts->count(); ++i )
{
int id = m_writeablePorts->idAt( i );
if( m_writeablePorts->isItemChecked( id ) )
{
wp += m_writeablePorts->text( id ) + ",";
}
}
// cut off comma
if( wp.length() > 0 )
{
wp.truncate( wp.length() - 1 );
}
mw_de.setAttribute( "outports", wp );
}
_parent.appendChild( mw_de );
}
@@ -200,7 +228,40 @@ void midiTabWidget::loadSettings( const QDomElement & _this )
).toInt() );
m_receiveCheckBox->setChecked( _this.attribute( "receive" ).toInt() );
m_sendCheckBox->setChecked( _this.attribute( "send" ).toInt() );
m_routeCheckBox->setChecked( _this.attribute( "route" ).toInt() );
// restore connections
QStringList rp = QStringList::split( ',', _this.attribute(
"inports" ) );
if( m_readablePorts != NULL && m_receiveCheckBox->isChecked() == TRUE )
{
for( csize i = 0; i < m_readablePorts->count(); ++i )
{
int id = m_readablePorts->idAt( i );
if( m_readablePorts->isItemChecked( id ) !=
( rp.find( m_readablePorts->text( id ) ) !=
rp.end() ) )
{
activatedReadablePort( id );
}
}
}
QStringList wp = QStringList::split( ',', _this.attribute(
"outports" ) );
if( m_writeablePorts != NULL && m_sendCheckBox->isChecked() == TRUE )
{
for( csize i = 0; i < m_writeablePorts->count(); ++i )
{
int id = m_writeablePorts->idAt( i );
if( m_writeablePorts->isItemChecked( id ) !=
( wp.find( m_writeablePorts->text( id ) ) !=
wp.end() ) )
{
activatedWriteablePort( id );
}
}
}
}

View File

@@ -23,6 +23,12 @@
*/
#include <config.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include "mixer.h"
#include "play_handle.h"
#include "song_editor.h"
@@ -53,6 +59,39 @@
Uint32 SAMPLE_RATES[QUALITY_LEVELS] = { 44100, 88200 } ;
class microTimer
{
public:
microTimer( void )
{
reset();
}
~microTimer()
{
}
void reset( void )
{
gettimeofday( &begin, NULL );
}
Uint32 elapsed( void ) const
{
struct timeval now;
gettimeofday( &now, NULL );
return( ( now.tv_sec - begin.tv_sec ) * 1000 * 1000 +
( now.tv_usec - begin.tv_usec ) );
}
private:
struct timeval begin;
} ;
mixer * mixer::s_instanceOfMe = NULL;
@@ -61,6 +100,7 @@ mixer::mixer() :
m_framesPerAudioBuffer( DEFAULT_BUFFER_SIZE ),
m_curBuf( NULL ),
m_nextBuf( NULL ),
m_cpuLoad( 0 ),
m_qualityLevel( DEFAULT_QUALITY_LEVEL ),
m_masterGain( 1.0f ),
m_audioDev( NULL ),
@@ -125,6 +165,12 @@ void mixer::stopProcessing( void )
const surroundSampleFrame * mixer::renderNextBuffer( void )
{
microTimer timer;
// now we have to make sure no other thread does anything bad
// while we're acting...
m_mixMutex.lock();
// remove all play-handles that have to be deleted and delete
// them if they still exist...
// maybe this algorithm could be optimized...
@@ -147,10 +193,6 @@ const surroundSampleFrame * mixer::renderNextBuffer( void )
m_playHandlesToRemove.begin() );
}
// 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 );
@@ -201,6 +243,10 @@ const surroundSampleFrame * mixer::renderNextBuffer( void )
// and trigger LFOs
envelopeAndLFOWidget::triggerLFO();
const float new_cpu_load = timer.elapsed() / 10000.0f * sampleRate() /
m_framesPerAudioBuffer;
m_cpuLoad = tLimit( (int) ( new_cpu_load + m_cpuLoad ) / 2, 0, 100 );
return( m_curBuf );
}

View File

@@ -57,9 +57,10 @@ notePlayHandle::notePlayHandle( channelTrack * _chnl_trk, Uint32 _frames_ahead,
m_channelTrack->processOutEvent( midiEvent( NOTE_ON,
m_channelTrack->m_midiPort->outputChannel(),
key(),
tLimit<Uint16>(
(Uint16) ( ( getVolume() / 100.0f ) *
( m_channelTrack->getVolume() / 100.0f ) *
127 ) ),
127 ), 0, 127 ) ),
midiTime::fromFrames( m_framesAhead,
songEditor::inst()->framesPerTact() ) );
}
@@ -202,6 +203,13 @@ void notePlayHandle::checkValidity( void )
{
m_channelTrack = NULL;
}
// sub-notes might not be registered at mixer (for example arpeggio-
// notes), so they wouldn't invalidate them-selves
for( notePlayHandleVector::iterator it = m_subNotes.begin();
it != m_subNotes.end(); ++it )
{
( *it )->checkValidity();
}
}

View File

@@ -125,7 +125,7 @@ pianoRoll::pianoRollKeyTypes pianoRoll::prKeyOrder[] =
} ;
const int DEFAULT_PR_PPT = KEY_LINE_HEIGHT * MAX_BEATS_PER_TACT;
const int DEFAULT_PR_PPT = KEY_LINE_HEIGHT * DEFAULT_STEPS_PER_TACT;
pianoRoll::pianoRoll( void ) :
@@ -779,9 +779,9 @@ void pianoRoll::paintEvent( QPaintEvent * )
// draw vertical raster
int tact_16th = m_currentPosition / 4;
int offset = ( m_currentPosition % 4 ) * m_ppt /
MAX_BEATS_PER_TACT / 4;
DEFAULT_STEPS_PER_TACT / 4;
for( int x = WHITE_KEY_WIDTH - offset; x < width();
x += m_ppt/MAX_BEATS_PER_TACT, ++tact_16th )
x += m_ppt / DEFAULT_STEPS_PER_TACT, ++tact_16th )
{
if( x >= WHITE_KEY_WIDTH )
{
@@ -1800,8 +1800,9 @@ void pianoRoll::keyPressEvent( QKeyEvent * _ke )
{
if( ( m_timeLine->pos() -= 16 ) < 0 )
{
m_timeLine->pos() = 0;
}
m_timeLine->pos().setTact( 0 );
m_timeLine->pos().setTact64th( 0 );
}
m_timeLine->updatePosition();
break;
}
@@ -1890,7 +1891,8 @@ void pianoRoll::keyPressEvent( QKeyEvent * _ke )
break;
case Qt::Key_Home:
m_timeLine->pos() = 0;
m_timeLine->pos().setTact( 0 );
m_timeLine->pos().setTact64th( 0 );
m_timeLine->updatePosition();
break;
@@ -1920,7 +1922,7 @@ void pianoRoll::wheelEvent( QWheelEvent * _we )
if( _we->delta() > 0 )
{
m_ppt = tMin( m_ppt * 2, KEY_LINE_HEIGHT *
MAX_BEATS_PER_TACT * 8 );
DEFAULT_STEPS_PER_TACT * 8 );
}
else if( m_ppt >= 72 )
{

View File

@@ -44,6 +44,8 @@
#include "track_container.h"
#include "mmp.h"
#include "debug.h"
#include "midi_port.h"
// invisible track-container which is needed as parents for preview-channels
@@ -126,12 +128,15 @@ presetPreviewPlayHandle::presetPreviewPlayHandle(
s_globalChannelTrack->loadTrackSpecificSettings( mmp.content().
firstChild().
toElement() );
// make sure, our preset-preview-track does not appear in any MIDI-
// devices list, so just disable receiving/sending MIDI-events at all
s_globalChannelTrack->m_midiPort->setMode( midiPort::DUMMY );
// create temporary note
note n( 0, 0, static_cast<tones>( A ),
static_cast<octaves>( DEFAULT_OCTAVE-1 ), 100 );
// create note-play-handle for it
m_previewNote = new notePlayHandle( s_globalChannelTrack, 0, ~0, &n );
//m_previewNote->setFrames( mixer::inst()->sampleRate() );
s_globalPreviewNote = m_previewNote;
@@ -151,7 +156,6 @@ presetPreviewPlayHandle::~presetPreviewPlayHandle()
}
delete m_previewNote;
s_globalDataMutex->unlock();
//blindTrackContainer::inst()->removeTrack( m_channelTrack );
}

View File

@@ -46,10 +46,8 @@
#include <QLabel>
#include <QStatusBar>
#include <QAction>
#include <QToolBar>
#include <QComboBox>
#include <QLayout>
#include <QToolButton>
#else
@@ -64,7 +62,6 @@
#include <qstatusbar.h>
#include <qcombobox.h>
#include <qlayout.h>
#include <qtoolbutton.h>
#endif
@@ -90,6 +87,7 @@
#include "lcd_spinbox.h"
#include "tooltip.h"
#include "tool_button.h"
#include "cpuload_widget.h"
#include "debug.h"
@@ -157,42 +155,13 @@ 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 );
// add some essential widgets to global tool-bar
QWidget * tb = lmmsMainWin::inst()->toolBar();
lmmsMainWin::inst()->addSpacingToToolBar( 10 );
#ifdef QT4
containerWidget()->setParent( cw );
#else
containerWidget()->reparent( cw, 0, QPoint( 0, 0 ) );
#endif
containerWidget()->move( 0, m_toolBar->height() + tl->height() );
QToolBar * main_tb = lmmsMainWin::inst()->mainToolBar();
// spacer-item
( new QWidget( main_tb ) )->setFixedSize( 10, 1 );
QLabel * bpm_label = new QLabel( main_tb );
bpm_label->setPixmap( embed::getIconPixmap( "clock" ) );
// spacer-item
( new QWidget( main_tb ) )->setFixedSize( 8, 1 );
m_bpmSpinBox = new lcdSpinBox( MIN_BPM, MAX_BPM, 3, main_tb );
#ifdef QT4
main_tb->addWidget( m_bpmSpinBox );
main_tb->addWidget( bpm_label );
#endif
m_bpmSpinBox = new lcdSpinBox( MIN_BPM, MAX_BPM, 3, tb );
m_bpmSpinBox->setLabel( tr( "TEMPO/BPM" ) );
connect( m_bpmSpinBox, SIGNAL( valueChanged( int ) ), this,
SLOT( setBPM( int ) ) );
@@ -210,30 +179,37 @@ songEditor::songEditor() :
"should be played within a minute (or how many tacts "
"should be played within four minutes)." ) );
// spacer-item
( new QWidget( main_tb ) )->setFixedSize( 10, 1 );
int col = lmmsMainWin::inst()->addWidgetToToolBar( m_bpmSpinBox, 0 );
main_tb->addSeparator();
toolButton * hq_btn = new toolButton( embed::getIconPixmap( "hq_mode" ),
tr( "High quality mode" ),
NULL, NULL, tb );
hq_btn->setToggleButton( TRUE );
connect( hq_btn, SIGNAL( toggled( bool ) ), mixer::inst(),
SLOT( setHighQuality( bool ) ) );
hq_btn->setFixedWidth( 42 );
lmmsMainWin::inst()->addWidgetToToolBar( hq_btn, 1, col );
QLabel * master_vol_lbl = new QLabel( main_tb );
lmmsMainWin::inst()->addSpacingToToolBar( 10 );
QLabel * master_vol_lbl = new QLabel( tb );
master_vol_lbl->setPixmap( embed::getIconPixmap( "master_volume" ) );
#ifdef QT4
m_masterVolumeSlider = new QSlider( Qt::Vertical, main_tb );
m_masterVolumeSlider = new QSlider( Qt::Vertical, tb );
m_masterVolumeSlider->setRange( 0, 200 );
m_masterVolumeSlider->setPageStep( 10 );
m_masterVolumeSlider->setValue( 100 );
m_masterVolumeSlider->setTickPosition( QSlider::TicksLeft );
main_tb->addWidget( master_vol_lbl );
main_tb->addWidget( m_masterVolumeSlider );
#else
m_masterVolumeSlider = new QSlider( 0, 200, 10, 100, Qt::Vertical,
main_tb );
m_masterVolumeSlider = new QSlider( 0, 200, 10, 100, Qt::Vertical, tb );
m_masterVolumeSlider->setTickPosition( QSlider::Left );
#endif
m_masterVolumeSlider->setFixedSize( 26, 48 );
m_masterVolumeSlider->setFixedSize( 26, 60 );
m_masterVolumeSlider->setTickInterval( 50 );
toolTip::add( m_masterVolumeSlider, tr( "master output volume" ) );
@@ -246,27 +222,26 @@ songEditor::songEditor() :
connect( m_masterVolumeSlider, SIGNAL( sliderReleased() ), this,
SLOT( masterVolumeReleased() ) );
lmmsMainWin::inst()->addWidgetToToolBar( master_vol_lbl );
lmmsMainWin::inst()->addWidgetToToolBar( m_masterVolumeSlider );
// spacer-item
( new QWidget( main_tb ) )->setFixedSize( 10, 1 );
QLabel * master_pitch_lbl = new QLabel( main_tb );
lmmsMainWin::inst()->addSpacingToToolBar( 10 );
QLabel * master_pitch_lbl = new QLabel( tb );
master_pitch_lbl->setPixmap( embed::getIconPixmap( "master_pitch" ) );
#ifdef QT4
m_masterPitchSlider = new QSlider( Qt::Vertical, main_tb );
m_masterPitchSlider = new QSlider( Qt::Vertical, tb );
m_masterPitchSlider->setRange( -12, 12 );
m_masterPitchSlider->setPageStep( 1 );
m_masterPitchSlider->setValue( 0 );
m_masterPitchSlider->setTickPosition( QSlider::TicksLeft );
main_tb->addWidget( master_pitch_lbl );
main_tb->addWidget( m_masterPitchSlider );
#else
m_masterPitchSlider = new QSlider( -12, 12, 1, 0, Qt::Vertical,
main_tb);
m_masterPitchSlider = new QSlider( -12, 12, 1, 0, Qt::Vertical, tb );
m_masterPitchSlider->setTickPosition( QSlider::Left );
#endif
m_masterPitchSlider->setFixedSize( 26, 48 );
m_masterPitchSlider->setFixedSize( 26, 60 );
m_masterPitchSlider->setTickInterval( 12 );
toolTip::add( m_masterPitchSlider, tr( "master pitch" ) );
connect( m_masterPitchSlider, SIGNAL( valueChanged( int ) ), this,
@@ -278,35 +253,45 @@ songEditor::songEditor() :
connect( m_masterPitchSlider, SIGNAL( sliderReleased() ), this,
SLOT( masterPitchReleased() ) );
// spacer-item
( new QWidget( main_tb ) )->setFixedSize( 5, 1 );
lmmsMainWin::inst()->addWidgetToToolBar( master_pitch_lbl );
lmmsMainWin::inst()->addWidgetToToolBar( m_masterPitchSlider );
main_tb->addSeparator();
lmmsMainWin::inst()->addSpacingToToolBar( 10 );
// create widget for visualization- and cpu-load-widget
QWidget * vc_w = new QWidget( tb );
QVBoxLayout * vcw_layout = new QVBoxLayout( vc_w );
vcw_layout->addStretch();
vcw_layout->addWidget( new visualizationWidget(
embed::getIconPixmap( "output_graph" ), vc_w ) );
vcw_layout->addWidget( new cpuloadWidget( vc_w ) );
vcw_layout->addStretch();
lmmsMainWin::inst()->addWidgetToToolBar( vc_w );
// create own 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 );
// spacer-item
( new QWidget( main_tb ) )->setFixedSize( 5, 1 );
m_masterOutputGraph = new visualizationWidget( embed::getIconPixmap(
"output_graph" ), main_tb );
#ifdef QT4
main_tb->addWidget( m_masterOutputGraph );
containerWidget()->setParent( cw );
#else
containerWidget()->reparent( cw, 0, QPoint( 0, 0 ) );
#endif
// 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,
main_tb );
hq->setToggleButton( TRUE );
connect( hq, SIGNAL( toggled( bool ) ), mixer::inst(),
SLOT( setHighQuality( bool ) ) );
containerWidget()->move( 0, m_toolBar->height() + tl->height() );
// fill own tool-bar
m_playButton = new toolButton( embed::getIconPixmap( "play" ),
tr( "Play song (Space)" ),
this, SLOT( play() ), m_toolBar );
@@ -817,7 +802,8 @@ void songEditor::doActions( void )
}
// a second switch for saving pos when starting to play
// anything
// anything (need pos for restoring it later in certain
// timeline-modes)
switch( m_actions.front() )
{
case ACT_PLAY_SONG:
@@ -1241,7 +1227,7 @@ void songEditor::addSampleTrack( void )
float songEditor::framesPerTact( void ) const
{
return( mixer::inst()->sampleRate() * 60.0f * MAIN_BEATS_PER_TACT /
return( mixer::inst()->sampleRate() * 60.0f * BEATS_PER_TACT /
m_bpmSpinBox->value() );
}
@@ -1316,7 +1302,6 @@ void songEditor::clearProject( void )
// access non existing data (as you can see in the next lines,
// all data is cleared!)
stop();
doActions();
}
// make sure all running notes are cleared, otherwise the whole
@@ -1324,6 +1309,7 @@ void songEditor::clearProject( void )
//mixer::inst()->clear();
while( mixer::inst()->haveNoRunningNotes() == FALSE )
{
/* qApp->processEvents();*/
}
trackVector tv = tracks();

View File

@@ -32,18 +32,19 @@
#include <QApplication>
#include <QMouseEvent>
#include <QLayout>
#include <QTimer>
#else
#include <qpainter.h>
#include <qapplication.h>
#include <qlayout.h>
#include <qtimer.h>
#endif
#include "timeline.h"
#include "nstate_button.h"
#include "embed.h"
#include "templates.h"
#include "nstate_button.h"
@@ -63,6 +64,7 @@ timeLine::timeLine( const int _xoff, const int _yoff, const float _ppt,
m_autoScroll( AUTOSCROLL_ENABLED ),
m_loopPoints( LOOP_POINTS_DISABLED ),
m_behaviourAtStop( BACK_TO_ZERO ),
m_changedPosition( TRUE ),
m_xOffset( _xoff ),
m_posMarkerX( 0 ),
m_ppt( _ppt ),
@@ -109,6 +111,10 @@ timeLine::timeLine( const int _xoff, const int _yoff, const float _ppt,
m_pos.m_timeLine = this;
updatePosition();
QTimer * update_timer = new QTimer( this );
connect( update_timer, SIGNAL( timeout() ), this,
SLOT( checkForUpdatedPosition() ) );
update_timer->start( 50 );
}
@@ -173,13 +179,7 @@ void timeLine::updatePosition( const midiTime & )
if( new_x != m_posMarkerX )
{
m_posMarkerX = new_x;
#ifndef QT4
qApp->lock();
#endif
paintEvent( NULL );
#ifndef QT4
qApp->unlock();
#endif
m_changedPosition = TRUE;
if( m_autoScroll == AUTOSCROLL_ENABLED )
{
emit positionChanged( m_pos );
@@ -215,6 +215,18 @@ void timeLine::toggleBehaviourAtStop( int _n )
void timeLine::checkForUpdatedPosition( void )
{
if( m_changedPosition == TRUE )
{
repaint();
m_changedPosition = FALSE;
}
}
void timeLine::paintEvent( QPaintEvent * )
{
#ifdef QT4

View File

@@ -47,10 +47,12 @@
multimediaProject::typeDescStruct multimediaProject::s_types[multimediaProject::PROJ_TYPE_COUNT] =
multimediaProject::typeDescStruct
multimediaProject::s_types[multimediaProject::PROJ_TYPE_COUNT] =
{
{ multimediaProject::UNKNOWN, "unknown" },
{ multimediaProject::SONG_PROJECT, "song" },
{ multimediaProject::SONG_PROJECT_TEMPLATE, "songtemplate" },
{ multimediaProject::CHANNEL_SETTINGS, "channelsettings" },
{ multimediaProject::EFFECT_SETTINGS, "effectsettings" },
{ multimediaProject::VIDEO_PROJECT, "video" },
@@ -176,9 +178,19 @@ bool multimediaProject::writeFile( const QString & _fn, bool _overwrite_check )
fn += ".cs.xml";
}
}
else if( fn.section( '.',-1 ) != "xml" )
else if( type() == SONG_PROJECT )
{
fn += ".xml";
if( fn.section( '.',-1 ) != "mmp" )
{
fn += ".mmp";
}
}
else if( type() == SONG_PROJECT_TEMPLATE )
{
if( fn.section( '.',-1 ) != "mpt" )
{
fn += ".mpt";
}
}

View File

@@ -89,7 +89,7 @@ midiALSARaw::~midiALSARaw()
if( running() )
{
m_quit = TRUE;
wait( 500 );
wait( 1000 );
terminate();
snd_rawmidi_close( m_input );

View File

@@ -114,7 +114,7 @@ midiALSASeq::~midiALSASeq()
if( running() )
{
m_quit = TRUE;
wait( 500 );
wait( 1000 );
terminate();
snd_seq_stop_queue( m_seqHandle, m_queueID, NULL );

View File

@@ -84,7 +84,7 @@ midiOSS::~midiOSS()
if( running() )
{
m_quit = TRUE;
wait( 500 );
wait( 1000 );
terminate();
}
}

View File

@@ -85,7 +85,7 @@ void midiPort::processOutEvent( const midiEvent & _me, const midiTime & _time )
{
// mask event
if( ( mode() == OUTPUT || mode() == DUPLEX ) &&
( outputChannel() == _me.m_channel || outputChannel() == -1 ) )
( outputChannel() == _me.m_channel && outputChannel() != -1 ) )
{
m_midiClient->processOutEvent( _me, _time, this );
}

View File

@@ -34,6 +34,7 @@
#include <QMessageBox>
#include <QImage>
#include <QMouseEvent>
#include <QTimer>
#else
@@ -43,6 +44,10 @@
#include <qpushbutton.h>
#include <qmessagebox.h>
#include <qimage.h>
#include <qtimer.h>
#define addSeparator insertSeparator
#define addMenu insertItem
#endif
@@ -75,35 +80,13 @@ pattern::pattern ( channelTrack * _channel_track ) :
m_channelTrack( _channel_track ),
m_patternType( BEAT_PATTERN ),
m_name( _channel_track->name() ),
m_steps( DEFAULT_STEPS_PER_TACT ),
m_frozenPatternMutex(),
m_frozenPattern( NULL ),
m_freezing( FALSE ),
m_freezeAborted( FALSE )
{
initPixmaps();
setFixedHeight( s_patternBg->height() + 4 );
#ifndef QT4
// set background-mode for flicker-free redraw
setBackgroundMode( Qt::NoBackground );
#endif
if( m_patternType == BEAT_PATTERN )
{
for( int i = 0; i < MAX_BEATS_PER_TACT; ++i )
{
m_notes.push_back( new note( midiTime( 0 ),
midiTime( i*4 ) ) );
}
}
changeLength( length() );
setAutoResizeEnabled( FALSE );
toolTip::add( this,
tr( "double-click to open this pattern in piano-roll" ) );
init();
}
@@ -114,27 +97,18 @@ pattern::pattern( const pattern & _pat_to_copy ) :
m_channelTrack( _pat_to_copy.m_channelTrack ),
m_patternType( _pat_to_copy.m_patternType ),
m_name( "" ),
m_steps( _pat_to_copy.m_steps ),
m_frozenPatternMutex(),
m_frozenPattern( NULL ),
m_freezeAborted( FALSE )
{
initPixmaps();
for( noteVector::const_iterator it = _pat_to_copy.m_notes.begin();
it != _pat_to_copy.m_notes.end(); ++it )
{
m_notes.push_back( new note( **it ) );
}
setFixedHeight( s_patternBg->height() + 4 );
#ifndef QT4
// set background-mode for flicker-free redraw
setBackgroundMode( Qt::NoBackground );
#endif
changeLength( length() );
setAutoResizeEnabled( FALSE );
init();
}
@@ -162,7 +136,7 @@ pattern::~pattern()
void pattern::initPixmaps( void )
void pattern::init( void )
{
if( s_patternBg == NULL )
{
@@ -188,6 +162,21 @@ void pattern::initPixmaps( void )
{
s_frozen = new QPixmap( embed::getIconPixmap( "frozen" ) );
}
ensureBeatNotes();
#ifndef QT4
// set background-mode for flicker-free redraw
setBackgroundMode( Qt::NoBackground );
#endif
setFixedHeight( s_patternBg->height() + 4 );
changeLength( length() );
setAutoResizeEnabled( FALSE );
toolTip::add( this,
tr( "double-click to open this pattern in piano-roll" ) );
}
@@ -222,32 +211,47 @@ void pattern::constructContextMenu( QMenu * _cm )
_cm->insertSeparator( 1 );
#endif
#ifdef QT4
_cm->addSeparator();
#else
_cm->insertSeparator();
#endif
_cm->addAction( embed::getIconPixmap( "edit_erase" ),
tr( "Clear all notes" ), this, SLOT( clear() ) );
#ifdef QT4
_cm->addSeparator();
#else
_cm->insertSeparator();
#endif
_cm->addAction( embed::getIconPixmap( "reload" ), tr( "Reset name" ),
this, SLOT( resetName() ) );
_cm->addAction( embed::getIconPixmap( "rename" ), tr( "Change name" ),
this, SLOT( changeName() ) );
#ifdef QT4
_cm->addSeparator();
#else
_cm->insertSeparator();
#endif
_cm->addAction( embed::getIconPixmap( "freeze" ),
( m_frozenPattern != NULL )? tr( "Refreeze" ) : tr( "Freeze" ),
this, SLOT( freeze() ) );
_cm->addAction( embed::getIconPixmap( "unfreeze" ), tr( "Unfreeze" ),
this, SLOT( unfreeze() ) );
_cm->addSeparator();
QMenu * add_step_menu = new QMenu( this );
QMenu * remove_step_menu = new QMenu( this );
for( int i = 1; i <= 16; i *= 2 )
{
const QString label = ( i == 1 ) ?
tr( "1 step" ) :
tr( "%1 steps" ).arg( i );
int menu_id = add_step_menu->addAction( label, this,
SLOT( addSteps( int ) ) );
add_step_menu->setItemParameter( menu_id, i );
menu_id = remove_step_menu->addAction( label, this,
SLOT( removeSteps( int ) ) );
remove_step_menu->setItemParameter( menu_id, i );
}
_cm->addMenu( embed::getIconPixmap( "step_btn_add" ),
tr( "Add steps" ), add_step_menu );
_cm->addMenu( embed::getIconPixmap( "step_btn_remove" ),
tr( "Remove steps" ), remove_step_menu );
}
@@ -256,13 +260,14 @@ void pattern::constructContextMenu( QMenu * _cm )
void pattern::ensureBeatNotes( void )
{
// make sure, that all step-note exist
for( int i = 0; i < MAX_BEATS_PER_TACT; ++i )
for( int i = 0; i < m_steps; ++i )
{
bool found = FALSE;
for( noteVector::iterator it = m_notes.begin();
it != m_notes.end(); ++it )
{
if( ( *it )->pos() == i * 4 && ( *it )->length() <= 0 )
if( ( *it )->pos() == i * BEATS_PER_TACT &&
( *it )->length() <= 0 )
{
found = TRUE;
break;
@@ -270,7 +275,8 @@ void pattern::ensureBeatNotes( void )
}
if( found == FALSE )
{
addNote( note( midiTime( 0 ), midiTime( i * 4 ) ) );
addNote( note( midiTime( 0 ), midiTime( i *
BEATS_PER_TACT ) ) );
}
}
}
@@ -383,45 +389,47 @@ void pattern::paintEvent( QPaintEvent * )
}
}
}
else if( m_patternType == pattern::BEAT_PATTERN && ppt >= 192 )
else if( m_patternType == pattern::BEAT_PATTERN &&
( ppt >= 192 || m_steps != DEFAULT_STEPS_PER_TACT ) )
{
QPixmap stepon;
QPixmap stepoff;
QPixmap stepoffl;
int steps = length() / BEATS_PER_TACT;
#ifdef QT4
stepon = s_stepBtnOn->scaled( width() / 16,
stepon = s_stepBtnOn->scaled( width() / steps,
s_stepBtnOn->height(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation );
stepoff = s_stepBtnOff->scaled( width() / 16,
stepoff = s_stepBtnOff->scaled( width() / steps,
s_stepBtnOff->height(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation );
stepoffl = s_stepBtnOffLight->scaled( width() / 16,
stepoffl = s_stepBtnOffLight->scaled( width() / steps,
s_stepBtnOffLight->height(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation );
#else
stepon.convertFromImage( s_stepBtnOn->convertToImage().scale(
width() / 16, s_stepBtnOn->height() ) );
width() / steps, s_stepBtnOn->height() ) );
stepoff.convertFromImage( s_stepBtnOff->convertToImage().scale(
width() / 16, s_stepBtnOff->height() ) );
width() / steps, s_stepBtnOff->height() ) );
stepoffl.convertFromImage( s_stepBtnOffLight->convertToImage().
scale( width() / 16, s_stepBtnOffLight->height() ) );
scale( width() / steps,
s_stepBtnOffLight->height() ) );
#endif
for( noteVector::iterator it = m_notes.begin();
it != m_notes.end(); ++it )
{
Sint16 no = it - m_notes.begin();
Sint16 x = TCO_BORDER_WIDTH + static_cast<int>( no *
ppt /
m_notes.size() );
width() / steps );
Sint16 y = height() - s_stepBtnOn->height() - 1;
if( ( *it )->length() < 0 )
{
p.drawPixmap( x, y, stepon );
}
else if( ( no / 4 ) % 2 )
else if( ( no / BEATS_PER_TACT ) % 2 )
{
p.drawPixmap( x, y, stepoff );
}
@@ -459,11 +467,18 @@ void pattern::mousePressEvent( QMouseEvent * _me )
return;
}
if( m_patternType == pattern::BEAT_PATTERN && pixelsPerTact() >= 192 &&
if( m_patternType == pattern::BEAT_PATTERN &&
( pixelsPerTact() >= 192 ||
m_steps != DEFAULT_STEPS_PER_TACT ) &&
_me->y() > height() - s_stepBtnOn->height() )
{
note * n = m_notes[( _me->x() - TCO_BORDER_WIDTH ) * 16 /
width() ];
int step = ( _me->x() - TCO_BORDER_WIDTH ) *
length() / BEATS_PER_TACT / width();
if( step >= m_steps )
{
return;
}
note * n = m_notes[step];
if( n->length() < 0 )
{
n->setLength( 0 );
@@ -491,7 +506,8 @@ void pattern::mouseDoubleClickEvent( QMouseEvent * _me )
}
if( m_patternType == pattern::MELODY_PATTERN ||
!( m_patternType == pattern::BEAT_PATTERN &&
pixelsPerTact() >= 192 &&
( pixelsPerTact() >= 192 ||
m_steps != DEFAULT_STEPS_PER_TACT ) &&
_me->y() > height() - s_stepBtnOn->height() ) )
{
openInPianoRoll();
@@ -593,59 +609,8 @@ void pattern::freeze( void )
unfreeze();
}
// create and install audio-sample-recorder
bool b;
// 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() );
new patternFreezeThread( this );
// prepare stuff for playing correct things later
songEditor::inst()->playPattern( this, FALSE );
songEditor::playPos & ppp = songEditor::inst()->getPlayPos(
songEditor::PLAY_PATTERN );
ppp.setTact( 0 );
ppp.setTact64th( 0 );
ppp.setCurrentFrame( 0 );
ppp.m_timeLineUpdate = FALSE;
// create status-dialog
patternFreezeStatusDialog status_dlg;
status_dlg.show();
connect( &status_dlg, SIGNAL( aborted() ),
this, SLOT( abortFreeze() ) );
m_freezeAborted = FALSE;
m_freezing = TRUE;
// now render everything
while( ppp < length() && m_freezeAborted == FALSE )
{
freeze_recorder->processNextBuffer();
status_dlg.setProgress( ppp * 100 / length() );
qApp->processEvents();
}
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();
}
@@ -673,6 +638,41 @@ void pattern::abortFreeze( void )
void pattern::addSteps( int _n )
{
m_steps += _n;
ensureBeatNotes();
update();
}
void pattern::removeSteps( int _n )
{
if( _n < m_steps )
{
for( int i = m_steps - _n; i < m_steps; ++i )
{
for( noteVector::iterator it = m_notes.begin();
it != m_notes.end(); ++it )
{
if( ( *it )->pos() == i * BEATS_PER_TACT &&
( *it )->length() <= 0 )
{
removeNote( *it );
break;
}
}
}
m_steps -= _n;
update();
}
}
void pattern::playFrozenData( sampleFrame * _ab, Uint32 _start_frame,
Uint32 _frames )
{
@@ -692,9 +692,12 @@ midiTime pattern::length( void ) const
{
if( m_patternType == BEAT_PATTERN )
{
// TODO: remove this limitation later by adding
// "Add step to pattern"-option
return( 64 );
if( m_steps % DEFAULT_STEPS_PER_TACT == 0 )
{
return( m_steps * BEATS_PER_TACT );
}
return( ( m_steps / DEFAULT_STEPS_PER_TACT + 1 ) *
DEFAULT_STEPS_PER_TACT * BEATS_PER_TACT );
}
Sint32 max_length = 0;
@@ -920,6 +923,13 @@ void pattern::loadSettings( const QDomElement & _this )
}
node = node.nextSibling();
}
m_steps = _this.attribute( "steps" ).toInt();
if( m_steps == 0 )
{
m_steps = DEFAULT_STEPS_PER_TACT;
}
ensureBeatNotes();
/* if( _this.attribute( "frozen" ).toInt() )
{
@@ -931,8 +941,15 @@ void pattern::loadSettings( const QDomElement & _this )
patternFreezeStatusDialog::patternFreezeStatusDialog( void ) :
QDialog()
patternFreezeStatusDialog::patternFreezeStatusDialog( QThread * _thread ) :
QDialog(),
m_freezeThread( _thread )
{
setWindowTitle( tr( "Freezing pattern..." ) );
#if QT_VERSION >= 0x030200
@@ -954,6 +971,17 @@ patternFreezeStatusDialog::patternFreezeStatusDialog( void ) :
m_cancelBtn->show();
connect( m_cancelBtn, SIGNAL( clicked() ), this,
SLOT( cancelBtnClicked() ) );
show();
QTimer * update_timer = new QTimer( this );
connect( update_timer, SIGNAL( timeout() ),
this, SLOT( updateProgress() ) );
update_timer->start( 100 );
setWFlags( getWFlags() | Qt::WDestructiveClose );
connect( this, SIGNAL( aborted() ), this, SLOT( reject() ) );
}
@@ -961,6 +989,8 @@ patternFreezeStatusDialog::patternFreezeStatusDialog( void ) :
patternFreezeStatusDialog::~patternFreezeStatusDialog()
{
m_freezeThread->wait();
delete m_freezeThread;
}
@@ -969,11 +999,7 @@ patternFreezeStatusDialog::~patternFreezeStatusDialog()
void patternFreezeStatusDialog::setProgress( int _p )
{
#ifdef QT4
m_progressBar->setValue( _p );
#else
m_progressBar->setProgress( _p );
#endif
m_progress = _p;
}
@@ -991,6 +1017,109 @@ void patternFreezeStatusDialog::closeEvent( QCloseEvent * _ce )
void patternFreezeStatusDialog::cancelBtnClicked( void )
{
emit( aborted() );
done( -1 );
}
void patternFreezeStatusDialog::updateProgress( void )
{
if( m_progress < 0 )
{
done( 0 );
}
else
{
#ifdef QT4
m_progressBar->setValue( m_progress );
#else
m_progressBar->setProgress( m_progress );
#endif
}
}
patternFreezeThread::patternFreezeThread( pattern * _pattern ) :
QThread(),
m_pattern( _pattern )
{
m_statusDlg = new patternFreezeStatusDialog( this );
QObject::connect( m_statusDlg, SIGNAL( aborted() ),
m_pattern, SLOT( abortFreeze() ) );
start();
}
patternFreezeThread::~patternFreezeThread()
{
}
void patternFreezeThread::run( void )
{
// create and install audio-sample-recorder
bool b;
// 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( m_pattern, FALSE );
songEditor::playPos & ppp = songEditor::inst()->getPlayPos(
songEditor::PLAY_PATTERN );
ppp.setTact( 0 );
ppp.setTact64th( 0 );
ppp.setCurrentFrame( 0 );
ppp.m_timeLineUpdate = FALSE;
// create status-dialog
m_pattern->m_freezeAborted = FALSE;
m_pattern->m_freezing = TRUE;
// now render everything
while( ppp < m_pattern->length() &&
m_pattern->m_freezeAborted == FALSE )
{
freeze_recorder->processNextBuffer();
m_statusDlg->setProgress( ppp * 100 / m_pattern->length() );
}
m_pattern->m_freezing = FALSE;
// reset song-editor settings
songEditor::inst()->stop();
ppp.m_timeLineUpdate = TRUE;
// create final sample-buffer if freezing was successful
if( m_pattern->m_freezeAborted == FALSE )
{
m_pattern->m_frozenPatternMutex.lock();
freeze_recorder->createSampleBuffer(
&m_pattern->m_frozenPattern );
m_pattern->m_frozenPatternMutex.unlock();
}
// restore original audio-device
mixer::inst()->restoreAudioDevice();
m_statusDlg->setProgress( -1 ); // we're finished
}

View File

@@ -0,0 +1,96 @@
/*
* cpuload_widget.cpp - widget for displaying CPU-load (partly based on
* Hydrogen's CPU-load-widget)
*
* Copyright (c) 2005 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "cpuload_widget.h"
#include "embed.h"
#include "mixer.h"
cpuloadWidget::cpuloadWidget( QWidget * _parent ) :
QWidget( _parent ),
m_currentLoad( 0 ),
m_temp(),
m_background( embed::getIconPixmap( "cpuload_bg" ) ),
m_leds( embed::getIconPixmap( "cpuload_leds" ) ),
m_changed( TRUE ),
m_updateTimer()
{
setFixedSize( m_background.width(), m_background.height() );
m_temp.resize( width(), height() );
connect( &m_updateTimer, SIGNAL( timeout() ),
this, SLOT( updateCpuLoad() ) );
m_updateTimer.start( 100 ); // update player control at 10 fps
#ifndef QT4
setBackgroundMode( NoBackground );
#endif
}
cpuloadWidget::~cpuloadWidget()
{
}
void cpuloadWidget::paintEvent( QPaintEvent * )
{
if( m_changed == TRUE )
{
m_changed = FALSE;
// background
bitBlt( &m_temp, 0, 0, &m_background, 0, 0, width(), height(),
CopyROP );
// leds
bitBlt( &m_temp, 23, 3, &m_leds, 0, 0,
( m_leds.width() * m_currentLoad / 300 ) * 3,
m_leds.height(), CopyROP );
}
bitBlt( this, 0, 0, &m_temp, 0, 0, width(), height(), CopyROP );
}
void cpuloadWidget::updateCpuLoad()
{
// smooth load-values a bit
m_currentLoad = ( m_currentLoad + mixer::inst()->cpuLoad() ) / 2;
m_changed = TRUE;
update();
}
#include "cpuload_widget.moc"

View File

@@ -27,13 +27,8 @@
#ifdef QT4
#include <QPainter>
#include <QMouseEvent>
#else
#include <qpainter.h>
#endif
@@ -44,7 +39,7 @@
nStateButton::nStateButton( QWidget * _parent ) :
QPushButton( _parent ),
toolButton( _parent ),
m_generalToolTip( "" ),
m_curState( -1 )
{
@@ -103,38 +98,13 @@ void nStateButton::changeState( int _n )
/*
void nStateButton::paintEvent( QPaintEvent * )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap draw_pm( rect().size() );
draw_pm.fill( this, rect().topLeft() );
QPainter p( &draw_pm, this );
#endif
if( m_curState >= 0 && m_curState < (int) m_states.size() )
{
p.drawPixmap( 0, 0, *m_states[m_curState].first );
}
#ifndef QT4
// and blit all the drawn stuff on the screen...
bitBlt( this, rect().topLeft(), &draw_pm );
#endif
}
*/
void nStateButton::mousePressEvent( QMouseEvent * _me )
{
if( _me->button() == Qt::LeftButton && m_states.size() )
{
changeState( ( ++m_curState ) % m_states.size() );
}
QPushButton::mousePressEvent( _me );
toolButton::mousePressEvent( _me );
}