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

@@ -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 );
}