Merge remote-tracking branch 'origin/stable-0.4-test' into stable-0.4

Conflicts:
	include/song.h
	src/core/song.cpp
This commit is contained in:
Tobias Doerffel
2014-01-07 22:59:40 +01:00
186 changed files with 14877 additions and 1164 deletions

View File

@@ -1,7 +1,7 @@
/*
* AutomatableModel.cpp - some implementations of AutomatableModel-class
*
* Copyright (c) 2008-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2008-2012 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -44,6 +44,8 @@ AutomatableModel::AutomatableModel( DataType _type,
bool _default_constructed ) :
Model( _parent, _display_name, _default_constructed ),
m_dataType( _type ),
m_value( _val ),
m_initValue( _val ),
m_minValue( _min ),
m_maxValue( _max ),
m_step( _step ),

View File

@@ -2,7 +2,7 @@
* AutomationPattern.cpp - implementation of class AutomationPattern which
* holds dynamic values
*
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2008-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2006-2008 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
@@ -41,11 +41,9 @@
AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) :
trackContentObject( _auto_track ),
m_autoTrack( _auto_track ),
m_objects(),
m_hasAutomation( false )
m_objects()
{
changeLength( midiTime( 1, 0 ) );
m_timeMap[0] = 0;
}
@@ -54,8 +52,7 @@ AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) :
AutomationPattern::AutomationPattern( const AutomationPattern & _pat_to_copy ) :
trackContentObject( _pat_to_copy.m_autoTrack ),
m_autoTrack( _pat_to_copy.m_autoTrack ),
m_objects( _pat_to_copy.m_objects ),
m_hasAutomation( _pat_to_copy.m_hasAutomation )
m_objects( _pat_to_copy.m_objects )
{
for( timeMap::const_iterator it = _pat_to_copy.m_timeMap.begin();
it != _pat_to_copy.m_timeMap.end(); ++it )
@@ -100,13 +97,15 @@ void AutomationPattern::addObject( AutomatableModel * _obj, bool _search_dup )
if( addIt )
{
m_objects += _obj;
// been empty before?
if( m_objects.size() == 1 && !hasAutomation() )
if( m_objects.isEmpty() && hasAutomation() == false )
{
// then initialize default-value
// then initialize default value
putValue( 0, _obj->value<float>(), false );
}
m_objects += _obj;
connect( _obj, SIGNAL( destroyed( jo_id_t ) ),
this, SLOT( objectDestroyed( jo_id_t ) ),
Qt::DirectConnection );
@@ -152,6 +151,8 @@ midiTime AutomationPattern::putValue( const midiTime & _time,
const float _value,
const bool _quant_pos )
{
cleanObjects();
midiTime newTime = _quant_pos && engine::automationEditor() ?
note::quantized( _time,
engine::automationEditor()->quantization() ) :
@@ -159,44 +160,6 @@ midiTime AutomationPattern::putValue( const midiTime & _time,
m_timeMap[newTime] = _value;
if( newTime == 0 )
{
for( objectVector::iterator it = m_objects.begin();
it != m_objects.end(); )
{
if( *it )
{
( *it )->setValue( _value );
++it;
}
else
{
it = m_objects.erase( it );
}
}
}
// just one automation value?
if( m_timeMap.size() == 1 )
{
m_hasAutomation = m_objects.isEmpty(); // usually false
for( objectVector::iterator it = m_objects.begin();
it != m_objects.end(); ++it )
{
// default value differs from current value?
if( *it && _value != ( *it )->initValue<float>() )
{
// then enable automating this object
m_hasAutomation = true;
}
}
}
else
{
// in all other cases assume we have automation
m_hasAutomation = true;
}
// we need to maximize our length in case we're part of a hidden
// automation track as the user can't resize this pattern
if( getTrack() && getTrack()->type() == track::HiddenAutomationTrack )
@@ -214,41 +177,17 @@ midiTime AutomationPattern::putValue( const midiTime & _time,
void AutomationPattern::removeValue( const midiTime & _time )
{
if( _time != 0 )
cleanObjects();
m_timeMap.remove( _time );
if( getTrack() &&
getTrack()->type() == track::HiddenAutomationTrack )
{
m_timeMap.remove( _time );
if( m_timeMap.size() == 1 )
{
const float val = m_timeMap[0];
m_hasAutomation = false;
for( objectVector::iterator it = m_objects.begin();
it != m_objects.end(); )
{
if( *it )
{
( *it )->setValue( val );
if( ( *it )->initValue<float>() != val )
{
m_hasAutomation = true;
}
++it;
}
else
{
it = m_objects.erase( it );
}
}
}
if( getTrack() &&
getTrack()->type() == track::HiddenAutomationTrack )
{
changeLength( length() );
}
emit dataChanged();
changeLength( length() );
}
emit dataChanged();
}
@@ -260,10 +199,22 @@ float AutomationPattern::valueAt( const midiTime & _time ) const
{
return 0;
}
timeMap::const_iterator v = m_timeMap.lowerBound( _time );
if( m_timeMap.contains( _time ) )
{
return m_timeMap[_time];
}
// lowerBound returns next value with greater key, therefore we take
// the previous element to get the current value
return ( v != m_timeMap.begin() ) ? (v-1).value() : v.value();
timeMap::ConstIterator v = m_timeMap.lowerBound( _time );
if( v == m_timeMap.begin() )
{
return 0;
}
return (v-1).value();
}
@@ -325,18 +276,6 @@ void AutomationPattern::loadSettings( const QDomElement & _this )
}
}
m_hasAutomation = m_timeMap.size() > 0;
if( m_hasAutomation == false )
{
for( objectVector::iterator it = m_objects.begin();
it != m_objects.end(); ++it )
{
if( *it )
{
( *it )->setValue( m_timeMap[0] );
}
}
}
int len = _this.attribute( "len" ).toInt();
if( len <= 0 )
{
@@ -366,7 +305,7 @@ const QString AutomationPattern::name() const
void AutomationPattern::processMidiTime( const midiTime & _time )
{
if( _time >= 0 && m_hasAutomation )
if( _time >= 0 && hasAutomation() )
{
const float val = valueAt( _time );
for( objectVector::iterator it = m_objects.begin();
@@ -411,7 +350,7 @@ bool AutomationPattern::isAutomated( const AutomatableModel * _m )
{
const AutomationPattern * a =
dynamic_cast<const AutomationPattern *>( *j );
if( a && a->m_hasAutomation )
if( a && a->hasAutomation() )
{
for( objectVector::const_iterator k = a->m_objects.begin();
k != a->m_objects.end(); ++k )
@@ -502,9 +441,9 @@ void AutomationPattern::resolveAllIDs()
void AutomationPattern::clear()
{
const float val = firstObject()->value<float>();
m_timeMap.clear();
putValue( 0, val );
emit dataChanged();
if( engine::automationEditor() &&
engine::automationEditor()->currentPattern() == this )
@@ -537,6 +476,21 @@ void AutomationPattern::objectDestroyed( jo_id_t _id )
void AutomationPattern::cleanObjects()
{
for( objectVector::iterator it = m_objects.begin(); it != m_objects.end(); )
{
if( *it )
{
++it;
}
else
{
it = m_objects.erase( it );
}
}
}
#include "moc_AutomationPattern.cxx"

View File

@@ -1,7 +1,7 @@
/*
* InstrumentFunctions.cpp - models for instrument-function-tab
*
* Copyright (c) 2004-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -48,7 +48,7 @@ ChordCreator::ChordTable::Init ChordCreator::ChordTable::s_initTable[] =
{ QT_TRANSLATE_NOOP( "ChordCreator", "6" ), { 0, 4, 7, 9, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "6sus4" ), { 0, 5, 7, 9, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "6add9" ), { 0, 4, 7, 12, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "6add9" ), { 0, 4, 7, 9, 14, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "m6" ), { 0, 3, 7, 9, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "m6add9" ), { 0, 3, 7, 9, 14, -1 } },
@@ -56,11 +56,11 @@ ChordCreator::ChordTable::Init ChordCreator::ChordTable::s_initTable[] =
{ QT_TRANSLATE_NOOP( "ChordCreator", "7sus4" ), { 0, 5, 7, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7#5" ), { 0, 4, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7b5" ), { 0, 4, 6, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7#9" ), { 0, 4, 7, 10, 13, 18, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7b9" ), { 0, 4, 7, 10, 13, 16, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7#5#9" ), { 0, 4, 8, 12, 14, 19, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7#5b9" ), { 0, 4, 8, 12, 14, 17, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7b5b9" ), { 0, 4, 6, 10, 12, 15, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7#9" ), { 0, 4, 7, 10, 15, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7b9" ), { 0, 4, 7, 10, 13, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7#5#9" ), { 0, 4, 8, 10, 15, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7#5b9" ), { 0, 4, 8, 10, 13, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7b5b9" ), { 0, 4, 6, 10, 13, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7add11" ), { 0, 4, 7, 10, 17, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7add13" ), { 0, 4, 7, 10, 21, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "7#11" ), { 0, 4, 7, 10, 18, -1 } },
@@ -113,7 +113,7 @@ ChordCreator::ChordTable::Init ChordCreator::ChordTable::s_initTable[] =
{ QT_TRANSLATE_NOOP( "ChordCreator", "Melodic minor" ), { 0, 2, 3, 5, 7, 9, 11, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Whole tone" ), { 0, 2, 4, 6, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Diminished" ), { 0, 2, 3, 5, 6, 8, 9, 11, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Major pentatonic" ), { 0, 2, 4, 7, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Major pentatonic" ), { 0, 2, 4, 7, 9, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Minor pentatonic" ), { 0, 3, 5, 7, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Jap in sen" ), { 0, 1, 5, 7, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Major bebop" ), { 0, 2, 4, 5, 7, 8, 9, 11, -1 } },
@@ -130,6 +130,7 @@ ChordCreator::ChordTable::Init ChordCreator::ChordTable::s_initTable[] =
{ QT_TRANSLATE_NOOP( "ChordCreator", "Mixolydian" ), { 0, 2, 4, 5, 7, 9, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Aeolian" ), { 0, 2, 3, 5, 7, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Locrian" ), { 0, 1, 3, 5, 6, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "ChordCreator", "Minor" ), { 0, 2, 3, 5, 7, 8, 10, -1 } },
} ;

View File

@@ -35,7 +35,7 @@
#ifdef LMMS_HAVE_SCHED_H
#include <sched.h>
#endif
#include <QMutexLocker>
FileEncodeDevice __fileEncodeDevices[] =
{
@@ -126,6 +126,7 @@ ProjectRenderer::ExportFileFormats ProjectRenderer::getFileFormatFromExtension(
void ProjectRenderer::startProcessing()
{
if( isReady() )
{
// have to do mixer stuff with GUI-thread-affinity in order to
@@ -139,11 +140,11 @@ void ProjectRenderer::startProcessing()
QThread::HighPriority
#endif
);
}
}
void ProjectRenderer::run()
{
#if 0
@@ -157,6 +158,7 @@ void ProjectRenderer::run()
#endif
#endif
engine::getSong()->startExport();
song::playPos & pp = engine::getSong()->getPlayPos(

View File

@@ -230,14 +230,13 @@ bool RemotePlugin::process( const sampleFrame * _in_buf,
lock();
sendMessage( IdStartProcessing );
unlock();
if( m_failed || _out_buf == NULL || m_outputCount == 0 )
{
unlock();
return false;
}
lock();
waitForMessage( IdProcessingDone );
unlock();
@@ -314,7 +313,7 @@ void RemotePlugin::resizeSharedProcessingMemory()
#endif
}
int shm_key = 0;
static int shm_key = 0;
#ifdef USE_QT_SHMEM
do
{

View File

@@ -5,7 +5,7 @@
* This file is based on encode.c from vorbis-tools-source, for more information
* see below.
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -49,7 +49,7 @@ AudioFileOgg::AudioFileOgg( const sample_rate_t _sample_rate,
_nom_bitrate, _min_bitrate, _max_bitrate,
_depth, _mixer )
{
m_ok = _success_ful = startEncoding();
m_ok = _success_ful = outputFileOpened() && startEncoding();
}

View File

@@ -2,7 +2,7 @@
* AudioFileWave.cpp - audio-device which encodes wave-stream and writes it
* into a WAVE-file. This is used for song-export.
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -38,9 +38,10 @@ AudioFileWave::AudioFileWave( const sample_rate_t _sample_rate,
mixer * _mixer ) :
AudioFileDevice( _sample_rate, _channels, _file, _use_vbr,
_nom_bitrate, _min_bitrate, _max_bitrate,
_depth, _mixer )
_depth, _mixer ),
m_sf( NULL )
{
_success_ful = startEncoding();
_success_ful = outputFileOpened() && startEncoding();
}
@@ -68,7 +69,13 @@ bool AudioFileWave::startEncoding()
case 16:
default: m_si.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; break;
}
m_sf = sf_open( outputFile().toUtf8().constData(), SFM_WRITE, &m_si );
m_sf = sf_open(
#ifdef LMMS_BUILD_WIN32
outputFile().toLocal8Bit().constData(),
#else
outputFile().toUtf8().constData(),
#endif
SFM_WRITE, &m_si );
sf_set_string ( m_sf, SF_STR_SOFTWARE, "LMMS" );
return true;
}
@@ -110,6 +117,9 @@ void AudioFileWave::writeBuffer( const surroundSampleFrame * _ab,
void AudioFileWave::finishEncoding()
{
sf_close( m_sf );
if( m_sf )
{
sf_close( m_sf );
}
}

View File

@@ -270,7 +270,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels
int MainFilter, HighPass;
long NON, NT, TON, DiON, TDroop=0, DStep;
float a, b=0.f, c=0.f, d=0.f, g, TT=0.f, TL, NL, F1, F2, Fsync;
float a, b=0.f, c=0.f, d=0.f, g, TT=0.f, TL, NL, F1, F2;
float TphiStart=0.f, Tphi, TDroopRate, ddF, DAtten, DGain;
long BON, BON2, BFStep, BFStep2, botmp;
@@ -354,7 +354,6 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels
F1 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F1",200.0,dsfile) / Fs;
if(fabs(F1)<0.001f) F1=0.001f; //to prevent overtone ratio div0
F2 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F2",120.0,dsfile) / Fs;
Fsync = F2;
TDroopRate = GetPrivateProfileFloat(sec,"Droop",0.f,dsfile);
if(TDroopRate>0.f)
{

View File

@@ -1,7 +1,7 @@
/*
* fft_helpers.cpp - some functions around FFT analysis
*
* Copyright (c) 2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2008-2012 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -25,8 +25,6 @@
#include "fft_helpers.h"
#ifdef LMMS_HAVE_FFTW3F
#include <math.h>
@@ -243,5 +241,3 @@ float signalpower(float *timesignal, int num_values)
return power;
}
#endif

View File

@@ -1,7 +1,7 @@
/*
* MidiAlsaSeq.cpp - ALSA sequencer client
*
* Copyright (c) 2005-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2005-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -73,6 +73,7 @@ static QString __portName( snd_seq_t * _seq, const snd_seq_addr_t * _addr )
MidiAlsaSeq::MidiAlsaSeq() :
MidiClient(),
m_seqMutex(),
m_seqHandle( NULL ),
m_queueID( -1 ),
m_quit( false ),
@@ -131,9 +132,11 @@ MidiAlsaSeq::~MidiAlsaSeq()
m_quit = true;
wait( EventPollTimeOut*2 );
m_seqMutex.lock();
snd_seq_stop_queue( m_seqHandle, m_queueID, NULL );
snd_seq_free_queue( m_seqHandle, m_queueID );
snd_seq_close( m_seqHandle );
m_seqMutex.unlock();
}
}
@@ -228,8 +231,10 @@ void MidiAlsaSeq::processOutEvent( const midiEvent & _me,
return;
}
m_seqMutex.lock();
snd_seq_event_output( m_seqHandle, &ev );
snd_seq_drain_output( m_seqHandle );
m_seqMutex.unlock();
}
@@ -238,6 +243,8 @@ void MidiAlsaSeq::processOutEvent( const midiEvent & _me,
void MidiAlsaSeq::applyPortMode( MidiPort * _port )
{
m_seqMutex.lock();
// determine port-capabilities
unsigned int caps[2] = { 0, 0 };
@@ -297,6 +304,7 @@ void MidiAlsaSeq::applyPortMode( MidiPort * _port )
}
}
m_seqMutex.unlock();
}
@@ -304,6 +312,8 @@ void MidiAlsaSeq::applyPortMode( MidiPort * _port )
void MidiAlsaSeq::applyPortName( MidiPort * _port )
{
m_seqMutex.lock();
for( int i = 0; i < 2; ++i )
{
if( m_portIDs[_port][i] == -1 )
@@ -320,6 +330,8 @@ void MidiAlsaSeq::applyPortName( MidiPort * _port )
port_info );
snd_seq_port_info_free( port_info );
}
m_seqMutex.unlock();
}
@@ -329,8 +341,11 @@ void MidiAlsaSeq::removePort( MidiPort * _port )
{
if( m_portIDs.contains( _port ) )
{
m_seqMutex.lock();
snd_seq_delete_simple_port( m_seqHandle, m_portIDs[_port][0] );
snd_seq_delete_simple_port( m_seqHandle, m_portIDs[_port][1] );
m_seqMutex.unlock();
m_portIDs.remove( _port );
}
MidiClient::removePort( _port );
@@ -361,11 +376,16 @@ void MidiAlsaSeq::subscribeReadablePort( MidiPort * _port,
{
return;
}
m_seqMutex.lock();
snd_seq_addr_t sender;
if( snd_seq_parse_address( m_seqHandle, &sender,
_dest.section( ' ', 0, 0 ).toAscii().constData() ) )
{
fprintf( stderr, "error parsing sender-address!\n" );
m_seqMutex.unlock();
return;
}
snd_seq_port_info_t * port_info;
@@ -386,6 +406,8 @@ void MidiAlsaSeq::subscribeReadablePort( MidiPort * _port,
}
snd_seq_port_subscribe_free( subs );
snd_seq_port_info_free( port_info );
m_seqMutex.unlock();
}
@@ -406,11 +428,14 @@ void MidiAlsaSeq::subscribeWritablePort( MidiPort * _port,
return;
}
m_seqMutex.lock();
snd_seq_addr_t dest;
if( snd_seq_parse_address( m_seqHandle, &dest,
_dest.section( ' ', 0, 0 ).toAscii().constData() ) )
{
fprintf( stderr, "error parsing dest-address!\n" );
m_seqMutex.unlock();
return;
}
snd_seq_port_info_t * port_info;
@@ -431,6 +456,7 @@ void MidiAlsaSeq::subscribeWritablePort( MidiPort * _port,
}
snd_seq_port_subscribe_free( subs );
snd_seq_port_info_free( port_info );
m_seqMutex.unlock();
}
@@ -471,15 +497,20 @@ void MidiAlsaSeq::run()
break;
}
m_seqMutex.lock();
// while event queue is not empty
while( snd_seq_event_input_pending( m_seqHandle, true ) > 0 )
{
snd_seq_event_t * ev;
if( snd_seq_event_input( m_seqHandle, &ev ) < 0 )
{
m_seqMutex.unlock();
qCritical( "error while fetching MIDI event from sequencer" );
break;
}
m_seqMutex.unlock();
snd_seq_addr_t * source = NULL;
MidiPort * dest = NULL;
@@ -582,8 +613,12 @@ void MidiAlsaSeq::run()
break;
} // end switch
m_seqMutex.lock();
} // end while
m_seqMutex.unlock();
}
delete[] pollfd_set;
@@ -594,9 +629,13 @@ void MidiAlsaSeq::run()
void MidiAlsaSeq::changeQueueTempo( bpm_t _bpm )
{
m_seqMutex.lock();
snd_seq_change_queue_tempo( m_seqHandle, m_queueID,
60000000 / (int) _bpm, NULL );
snd_seq_drain_output( m_seqHandle );
m_seqMutex.unlock();
}
@@ -615,6 +654,9 @@ void MidiAlsaSeq::updatePortList()
snd_seq_port_info_malloc( &pinfo );
snd_seq_client_info_set_client( cinfo, -1 );
m_seqMutex.lock();
while( snd_seq_query_next_client( m_seqHandle, cinfo ) >= 0 )
{
int client = snd_seq_client_info_get_client( cinfo );
@@ -643,6 +685,9 @@ void MidiAlsaSeq::updatePortList()
}
}
m_seqMutex.unlock();
snd_seq_client_info_free( cinfo );
snd_seq_port_info_free( pinfo );

View File

@@ -222,11 +222,11 @@ void MidiClientRaw::parseData( const Uint8 _c )
m_midiParseData.m_buffer[0] - KeysPerOctave;
m_midiParseData.m_midiEvent.m_data.m_param[1] =
m_midiParseData.m_buffer[1];
break;
case MidiControlChange:
m_midiParseData.m_midiEvent.m_data.m_param[0] =
m_midiParseData.m_buffer[0] - KeysPerOctave;
m_midiParseData.m_midiEvent.m_data.m_param[1] =
m_midiParseData.m_buffer[1];
m_midiParseData.m_midiEvent.m_data.m_param[0] = m_midiParseData.m_buffer[0];
m_midiParseData.m_midiEvent.m_data.m_param[1] = m_midiParseData.m_buffer[1];
break;
case MidiPitchBend:

View File

@@ -2,7 +2,7 @@
* MidiPort.cpp - abstraction of MIDI-ports which are part of LMMS's MIDI-
* sequencing system
*
* Copyright (c) 2005-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2005-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -45,15 +45,17 @@ MidiPort::MidiPort( const QString & _name, MidiClient * _mc,
m_outputChannelModel( 1, 1, MidiChannelCount, this,
tr( "Output channel" ) ),
m_inputControllerModel( 0, 0, MidiControllerCount, this,
tr( "Input controller" ) ),
tr( "Input controller" ) ),
m_outputControllerModel( 0, 0, MidiControllerCount, this,
tr( "Output controller" ) ),
tr( "Output controller" ) ),
m_fixedInputVelocityModel( -1, -1, MidiMaxVelocity, this,
tr( "Fixed input velocity" ) ),
tr( "Fixed input velocity" ) ),
m_fixedOutputVelocityModel( -1, -1, MidiMaxVelocity, this,
tr( "Fixed output velocity" ) ),
m_fixedOutputNoteModel( -1, -1, MidiMaxNote, this,
tr( "Fixed output note" ) ),
m_outputProgramModel( 1, 1, MidiProgramCount, this,
tr( "Output MIDI program" ) ),
tr( "Output MIDI program" ) ),
m_readableModel( false, this, tr( "Receive MIDI-events" ) ),
m_writableModel( false, this, tr( "Send MIDI-events" ) )
{
@@ -127,20 +129,24 @@ void MidiPort::processInEvent( const midiEvent & _me, const midiTime & _time )
if( inputEnabled() &&
( inputChannel()-1 == _me.m_channel || inputChannel() == 0 ) )
{
midiEvent ev = _me;
if( _me.m_type == MidiNoteOn ||
_me.m_type == MidiNoteOff ||
_me.m_type == MidiKeyPressure )
{
if( _me.key() < 0 || _me.key() >= NumKeys )
ev.key() = ev.key() + KeysPerOctave;
if( ev.key() < 0 || ev.key() >= NumKeys )
{
return;
}
}
midiEvent ev = _me;
if( fixedInputVelocity() >= 0 && _me.velocity() > 0 )
{
ev.velocity() = fixedInputVelocity();
}
ev.setFromMidiPort( true );
m_midiEventProcessor->processInEvent( ev, _time );
}
}
@@ -156,9 +162,17 @@ void MidiPort::processOutEvent( const midiEvent & _me, const midiTime & _time )
midiEvent ev = _me;
// we use/display MIDI channels 1...16 but we need 0...15 for
// the outside world
if( ev.m_channel > 0 )
// We are already in "real" MIDI channel space here
/* if( ev.m_channel > 0 )
{
--ev.m_channel;
} */
if( ( _me.m_type == MidiNoteOn || _me.m_type == MidiNoteOff ) &&
fixedOutputNote() >= 0 )
{
// Convert MIDI note number (from spinbox) -> LMMS note number
// that will be converted back when outputted.
ev.key() = fixedOutputNote() - KeysPerOctave;
}
if( fixedOutputVelocity() >= 0 && _me.velocity() > 0 &&
( _me.m_type == MidiNoteOn ||
@@ -183,6 +197,8 @@ void MidiPort::saveSettings( QDomDocument & _doc, QDomElement & _this )
"fixedinputvelocity" );
m_fixedOutputVelocityModel.saveSettings( _doc, _this,
"fixedoutputvelocity" );
m_fixedOutputNoteModel.saveSettings( _doc, _this,
"fixedoutputnote" );
m_outputProgramModel.saveSettings( _doc, _this, "outputprogram" );
m_readableModel.saveSettings( _doc, _this, "readable" );
m_writableModel.saveSettings( _doc, _this, "writable" );

View File

@@ -190,6 +190,7 @@ void notePlayHandle::play( sampleFrame * _working_buffer )
}
if( m_released == false &&
instrumentTrack()->isSustainPedalPressed() == false &&
m_totalFramesPlayed + engine::getMixer()->framesPerPeriod()
>= m_frames )
{
@@ -293,7 +294,11 @@ void notePlayHandle::play( sampleFrame * _working_buffer )
f_cnt_t notePlayHandle::framesLeft() const
{
if( m_released && actualReleaseFramesToDo() == 0 )
if( instrumentTrack()->isSustainPedalPressed() )
{
return 4*engine::getMixer()->framesPerPeriod();
}
else if( m_released && actualReleaseFramesToDo() == 0 )
{
return m_framesBeforeRelease;
}

View File

@@ -1,7 +1,7 @@
/*
* sample_buffer.cpp - container-class sampleBuffer
*
* Copyright (c) 2005-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2005-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -699,8 +699,10 @@ f_cnt_t sampleBuffer::getLoopedIndex( f_cnt_t _index ) const
void sampleBuffer::visualize( QPainter & _p, const QRect & _dr,
const QRect & _clip )
const QRect & _clip, f_cnt_t _from_frame, f_cnt_t _to_frame )
{
const bool focus_on_range = _to_frame <= m_frames
&& 0 <= _from_frame && _from_frame < _to_frame;
// _p.setClipRect( _clip );
// _p.setPen( QColor( 0x22, 0xFF, 0x44 ) );
//_p.setPen( QColor( 64, 224, 160 ) );
@@ -709,25 +711,28 @@ void sampleBuffer::visualize( QPainter & _p, const QRect & _dr,
const int yb = h / 2 + _dr.y();
const float y_space = h*0.25f;
const int nb_frames = focus_on_range ? _to_frame - _from_frame : m_frames;
if( m_frames < 60000 )
if( nb_frames < 60000 )
{
_p.setRenderHint( QPainter::Antialiasing );
QColor c = _p.pen().color();
_p.setPen( QPen( c, 0.7 ) );
}
const int fpp = tLimit<int>( m_frames / w, 1, 20 );
QPoint * l = new QPoint[m_frames / fpp + 1];
const int fpp = tLimit<int>( nb_frames / w, 1, 20 );
QPoint * l = new QPoint[nb_frames / fpp + 1];
int n = 0;
const int xb = _dr.x();
for( int frame = 0; frame < m_frames; frame += fpp )
const int first = focus_on_range ? _from_frame : 0;
const int last = focus_on_range ? _to_frame : m_frames;
for( int frame = first; frame < last; frame += fpp )
{
l[n] = QPoint( xb + ( frame * w / m_frames ),
l[n] = QPoint( xb + ( (frame - first) * double( w ) / nb_frames ),
(int)( yb - ( ( m_data[frame][0]+m_data[frame][1] ) *
y_space ) ) );
++n;
}
_p.drawPolyline( l, m_frames / fpp );
_p.drawPolyline( l, nb_frames / fpp );
delete[] l;
}
@@ -737,6 +742,9 @@ void sampleBuffer::visualize( QPainter & _p, const QRect & _dr,
QString sampleBuffer::openAudioFile() const
{
QFileDialog ofd( NULL, tr( "Open audio file" ) );
#if QT_VERSION >= 0x040806
ofd.setOption( QFileDialog::DontUseCustomDirectoryIcons );
#endif
QString dir;
if( !m_audioFile.isEmpty() )

View File

@@ -1,7 +1,7 @@
/*
* song.cpp - root of the model tree
*
* Copyright (c) 2004-2011 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -61,6 +61,20 @@
#include "text_float.h"
#include "timeline.h"
#ifdef LMMS_BUILD_WIN32
#ifndef USE_QT_SHMEM
#define USE_QT_SHMEM
#endif
#endif
#ifndef USE_QT_SHMEM
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
tick_t midiTime::s_ticksPerTact = DefaultTicksPerTact;
@@ -81,6 +95,7 @@ song::song() :
m_modified( false ),
m_recording( false ),
m_exporting( false ),
m_exportLoop( false ),
m_playing( false ),
m_paused( false ),
m_loadingProject( false ),
@@ -88,7 +103,13 @@ song::song() :
m_length( 0 ),
m_trackToPlay( NULL ),
m_patternToPlay( NULL ),
m_loopPattern( false )
m_loopPattern( false ),
m_elapsedMilliSeconds( 0 ),
m_elapsedTicks( 0 ),
m_elapsedTacts( 0 ),
m_shmID( -1 ),
m_SncVSTplug( NULL ),
m_shmQtID( "/usr/bin/lmms" )
{
connect( &m_tempoModel, SIGNAL( dataChanged() ),
this, SLOT( setTempo() ) );
@@ -101,6 +122,59 @@ song::song() :
connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), this,
SLOT( updateFramesPerTick() ) );
// handle VST plugins sync
if( configManager::inst()->value( "ui", "syncvstplugins" ).toInt() )
{
connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), this,
SLOT( updateSampleRateSHM() ) );
#ifdef USE_QT_SHMEM
if ( !m_shmQtID.create( sizeof( sncVST ) ) )
{
fprintf(stderr, "song.cpp::m_shmQtID create SHM error: %s\n",
m_shmQtID.errorString().toStdString().c_str() );
}
m_SncVSTplug = (sncVST *) m_shmQtID.data();
#else
key_t key; // make the key:
if( ( key = ftok( VST_SNC_SHM_KEY_FILE, 'R' ) ) == -1 )
{
perror( "song.cpp::ftok" );
}
else
{ // connect to shared memory segment
if( ( m_shmID = shmget( key, sizeof( sncVST ),
0644 | IPC_CREAT ) ) == -1 )
{
perror( "song.cpp::shmget" );
}
else
{ // attach segment
m_SncVSTplug = (sncVST *)shmat(m_shmID, 0, 0);
if( m_SncVSTplug == (sncVST *)( -1 ) )
{
perror( "song.cpp::shmat" );
}
}
}
#endif
// if we are connected into shared memory
if( m_SncVSTplug != NULL )
{
m_SncVSTplug->isPlayin = m_playing | m_exporting;
m_SncVSTplug->hasSHM = true;
m_SncVSTplug->m_sampleRate =
engine::getMixer()->processingSampleRate();
m_SncVSTplug->m_bufferSize =
engine::getMixer()->framesPerPeriod();
m_SncVSTplug->timeSigNumer = 4;
m_SncVSTplug->timeSigDenom = 4;
}
} // end of VST plugin sync section
if( m_SncVSTplug == NULL )
{
m_SncVSTplug = (sncVST*) malloc( sizeof( sncVST ) );
}
connect( &m_masterVolumeModel, SIGNAL( dataChanged() ),
this, SLOT( masterVolumeChanged() ) );
@@ -108,7 +182,6 @@ song::song() :
this, SLOT( masterPitchChanged() ) );*/
qRegisterMetaType<note>( "note" );
}
@@ -116,6 +189,24 @@ song::song() :
song::~song()
{
// detach shared memory, delete it:
#ifdef USE_QT_SHMEM
m_shmQtID.detach();
#else
if( shmdt( m_SncVSTplug ) == -1)
{
if( m_SncVSTplug->hasSHM )
{
perror("~song::shmdt");
}
if( m_SncVSTplug != NULL )
{
delete m_SncVSTplug;
m_SncVSTplug = NULL;
}
}
shmctl(m_shmID, IPC_RMID, NULL);
#endif
m_playing = false;
delete m_globalAutomationTrack;
}
@@ -150,6 +241,13 @@ void song::setTempo()
engine::updateFramesPerTick();
m_SncVSTplug->m_bpm = tempo;
#ifdef VST_SNC_LATENCY
m_SncVSTplug->m_latency = m_SncVSTplug->m_bufferSize * tempo /
( (float) m_SncVSTplug->m_sampleRate * 60 );
#endif
emit tempoChanged( tempo );
}
@@ -162,6 +260,8 @@ void song::setTimeSignature()
emit timeSignatureChanged( m_oldTicksPerTact, ticksPerTact() );
emit dataChanged();
m_oldTicksPerTact = ticksPerTact();
m_SncVSTplug->timeSigNumer = getTimeSigModel().getNumerator();
m_SncVSTplug->timeSigDenom = getTimeSigModel().getDenominator();
}
@@ -171,6 +271,118 @@ void song::savePos()
{
timeLine * tl = m_playPos[m_playMode].m_timeLine;
while( !m_actions.empty() )
{
switch( m_actions.front() )
{
case ActionStop:
{
m_playing = false;
m_SncVSTplug->isPlayin = m_exporting;
m_recording = true;
if( tl != NULL )
{
switch( tl->behaviourAtStop() )
{
case timeLine::BackToZero:
m_playPos[m_playMode].setTicks( 0 );
m_elapsedMilliSeconds = 0;
break;
case timeLine::BackToStart:
if( tl->savedPos() >= 0 )
{
m_playPos[m_playMode].setTicks(
tl->savedPos().getTicks() );
m_elapsedMilliSeconds = (((tl->savedPos().getTicks())*60*1000/48)/getTempo());
tl->savePos( -1 );
}
break;
case timeLine::KeepStopPosition:
default:
break;
}
}
else
{
m_playPos[m_playMode].setTicks( 0 );
m_elapsedMilliSeconds = 0;
}
m_playPos[m_playMode].setCurrentFrame( 0 );
// remove all note-play-handles that are active
engine::getMixer()->clear();
break;
}
case ActionPlaySong:
m_playMode = Mode_PlaySong;
m_playing = true;
m_SncVSTplug->isPlayin = true;
Controller::resetFrameCounter();
break;
case ActionPlayTrack:
m_playMode = Mode_PlayTrack;
m_playing = true;
m_SncVSTplug->isPlayin = true;
break;
case ActionPlayBB:
m_playMode = Mode_PlayBB;
m_playing = true;
m_SncVSTplug->isPlayin = true;
break;
case ActionPlayPattern:
m_playMode = Mode_PlayPattern;
m_playing = true;
m_SncVSTplug->isPlayin = true;
break;
case ActionPause:
m_playing = false;// just set the play-flag
m_SncVSTplug->isPlayin = m_exporting;
m_paused = true;
break;
case ActionResumeFromPause:
m_playing = true;// just set the play-flag
m_SncVSTplug->isPlayin = true;
m_paused = false;
break;
}
// a second switch for saving pos when starting to play
// anything (need pos for restoring it later in certain
// timeline-modes)
switch( m_actions.front() )
{
case ActionPlaySong:
case ActionPlayTrack:
case ActionPlayBB:
case ActionPlayPattern:
{
if( tl != NULL )
{
tl->savePos( m_playPos[m_playMode] );
}
break;
}
// keep GCC happy...
default:
break;
}
m_actions.erase( m_actions.begin() );
}
if( tl != NULL )
{
tl->savePos( m_playPos[m_playMode] );
@@ -246,6 +458,7 @@ void song::processNextBuffer()
if( m_playPos[m_playMode] < tl->loopBegin() ||
m_playPos[m_playMode] >= tl->loopEnd() )
{
m_elapsedMilliSeconds = (tl->loopBegin().getTicks()*60*1000/48)/getTempo();
m_playPos[m_playMode].setTicks(
tl->loopBegin().getTicks() );
}
@@ -257,8 +470,14 @@ void song::processNextBuffer()
while( total_frames_played
< engine::getMixer()->framesPerPeriod() )
{
f_cnt_t played_frames = engine::getMixer()
->framesPerPeriod() - total_frames_played;
f_cnt_t played_frames = ( m_SncVSTplug->m_bufferSize = engine::getMixer()
->framesPerPeriod() ) - total_frames_played;
#ifdef VST_SNC_LATENCY
m_SncVSTplug->m_latency = m_SncVSTplug->m_bufferSize *
m_SncVSTplug->m_bpm /
( (float) m_SncVSTplug->m_sampleRate * 60 );
#endif
float current_frame = m_playPos[m_playMode].currentFrame();
// did we play a tick?
@@ -266,6 +485,14 @@ void song::processNextBuffer()
{
int ticks = m_playPos[m_playMode].getTicks()
+ (int)( current_frame / frames_per_tick );
#ifdef VST_SNC_LATENCY
m_SncVSTplug->ppqPos = ( ( ticks + 0 ) / (float)48 ) -
m_SncVSTplug->m_latency;
#else
m_SncVSTplug->ppqPos = ( ( ticks + 0 ) / (float)48 );
#endif
// did we play a whole tact?
if( ticks >= midiTime::ticksPerTact() )
{
@@ -299,18 +526,38 @@ void song::processNextBuffer()
// offset
ticks = ticks % ( max_tact *
midiTime::ticksPerTact() );
#ifdef VST_SNC_LATENCY
m_SncVSTplug->ppqPos = ( ( ticks + 0 )
/ (float)48 )
- m_SncVSTplug->m_latency;
#else
m_SncVSTplug->ppqPos = ( ( ticks + 0 )
/ (float)48 );
#endif
}
}
m_playPos[m_playMode].setTicks( ticks );
if( check_loop )
{
m_SncVSTplug->isCycle = true;
m_SncVSTplug->cycleStart =
( tl->loopBegin().getTicks() )
/ (float)48;
m_SncVSTplug->cycleEnd =
( tl->loopEnd().getTicks() )
/ (float)48;
if( m_playPos[m_playMode] >= tl->loopEnd() )
{
m_playPos[m_playMode].setTicks(
tl->loopBegin().getTicks() );
m_elapsedMilliSeconds = ((tl->loopBegin().getTicks())*60*1000/48)/getTempo();
}
}
else
{
m_SncVSTplug->isCycle = false;
}
current_frame = fmodf( current_frame, frames_per_tick );
m_playPos[m_playMode].setCurrentFrame( current_frame );
@@ -358,6 +605,9 @@ void song::processNextBuffer()
total_frames_played += played_frames;
m_playPos[m_playMode].setCurrentFrame( played_frames +
current_frame );
m_elapsedMilliSeconds += (((played_frames/frames_per_tick)*60*1000/48)/getTempo());
m_elapsedTacts = m_playPos[Mode_PlaySong].getTact();
m_elapsedTicks = (m_playPos[Mode_PlaySong].getTicks()%ticksPerTact())/48;
}
}
@@ -511,6 +761,8 @@ void song::updateLength()
void song::setPlayPos( tick_t _ticks, PlayModes _play_mode )
{
m_elapsedTicks += m_playPos[_play_mode].getTicks() - _ticks;
m_elapsedMilliSeconds += (((( _ticks - m_playPos[_play_mode].getTicks()))*60*1000/48)/getTempo());
m_playPos[_play_mode].setTicks( _ticks );
m_playPos[_play_mode].setCurrentFrame( 0.0f );
}
@@ -592,6 +844,7 @@ void song::startExport()
playSong();
m_exporting = true;
m_SncVSTplug->isPlayin = true;
}
@@ -601,6 +854,8 @@ void song::stopExport()
{
stop();
m_exporting = false;
m_exportLoop = false;
m_SncVSTplug->isPlayin = m_playing;
}
@@ -1057,10 +1312,14 @@ void song::importProject()
tr("MIDI sequences") +
" (*.mid *.midi *.rmi);;" +
tr("FL Studio projects") +
" (*.flp"
");;" +
" (*.flp);;" +
tr("Hydrogen projects") +
" (*.h2song);;" +
tr("All file types") +
" (*.*)");
#if QT_VERSION >= 0x040806
ofd.setOption( QFileDialog::DontUseCustomDirectoryIcons );
#endif
ofd.setFileMode( QFileDialog::ExistingFiles );
if( ofd.exec () == QDialog::Accepted && !ofd.selectedFiles().isEmpty() )
@@ -1098,9 +1357,12 @@ void song::restoreControllerStates( const QDomElement & _this )
}
void song::exportProjectTracks()
{
exportProject(true);
}
void song::exportProject()
void song::exportProject(bool multiExport)
{
if( isEmpty() )
{
@@ -1113,38 +1375,54 @@ void song::exportProject()
}
QFileDialog efd( engine::mainWindow() );
efd.setFileMode( QFileDialog::AnyFile );
efd.setAcceptMode( QFileDialog::AcceptSave );
int idx = 0;
QStringList types;
while( __fileEncodeDevices[idx].m_fileFormat !=
ProjectRenderer::NumFileFormats )
#if QT_VERSION >= 0x040806
efd.setOption( QFileDialog::DontUseCustomDirectoryIcons );
#endif
if (multiExport)
{
types << tr( __fileEncodeDevices[idx].m_description );
++idx;
}
efd.setFilters( types );
QString base_filename;
if( !m_fileName.isEmpty() )
{
efd.setDirectory( QFileInfo( m_fileName ).absolutePath() );
base_filename = QFileInfo( m_fileName ).completeBaseName();
efd.setFileMode( QFileDialog::Directory);
efd.setWindowTitle( tr( "Select directory for writing exported tracks..." ) );
if( !m_fileName.isEmpty() )
{
efd.setDirectory( QFileInfo( m_fileName ).absolutePath() );
}
}
else
{
efd.setDirectory( configManager::inst()->userProjectsDir() );
base_filename = tr( "untitled" );
efd.setFileMode( QFileDialog::AnyFile );
int idx = 0;
QStringList types;
while( __fileEncodeDevices[idx].m_fileFormat !=
ProjectRenderer::NumFileFormats )
{
types << tr( __fileEncodeDevices[idx].m_description );
++idx;
}
efd.setFilters( types );
QString base_filename;
if( !m_fileName.isEmpty() )
{
efd.setDirectory( QFileInfo( m_fileName ).absolutePath() );
base_filename = QFileInfo( m_fileName ).completeBaseName();
}
else
{
efd.setDirectory( configManager::inst()->userProjectsDir() );
base_filename = tr( "untitled" );
}
efd.selectFile( base_filename + __fileEncodeDevices[0].m_extension );
efd.setWindowTitle( tr( "Select file for project-export..." ) );
}
efd.selectFile( base_filename + __fileEncodeDevices[0].m_extension );
efd.setWindowTitle( tr( "Select file for project-export..." ) );
efd.setAcceptMode( QFileDialog::AcceptSave );
if( efd.exec() == QDialog::Accepted &&
!efd.selectedFiles().isEmpty() && !efd.selectedFiles()[0].isEmpty() )
{
const QString export_file_name = efd.selectedFiles()[0];
exportProjectDialog epd( export_file_name,
engine::mainWindow() );
engine::mainWindow(), multiExport );
epd.exec();
}
}
@@ -1160,6 +1438,19 @@ void song::updateFramesPerTick()
void song::updateSampleRateSHM()
{
m_SncVSTplug->m_sampleRate = engine::getMixer()->processingSampleRate();
#ifdef VST_SNC_LATENCY
m_SncVSTplug->m_latency = m_SncVSTplug->m_bufferSize * m_SncVSTplug->m_bpm /
( (float) m_SncVSTplug->m_sampleRate * 60 );
#endif
}
void song::setModified()
{
if( !m_loadingProject )

View File

@@ -1,7 +1,7 @@
/*
* timeline.cpp - class timeLine, representing a time-line with position marker
*
* Copyright (c) 2004-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -324,6 +324,7 @@ void timeLine::mouseMoveEvent( QMouseEvent * _me )
{
case MovePositionMarker:
m_pos.setTicks( t.getTicks() );
engine::getSong()->setMilliSeconds(((((t.getTicks()))*60*1000/48)/engine::getSong()->getTempo()));
m_pos.setCurrentFrame( 0 );
updatePosition();
break;

View File

@@ -2,7 +2,7 @@
* track.cpp - implementation of classes concerning tracks -> necessary for
* all track-like objects (beat/bassline, sample-track...)
*
* Copyright (c) 2004-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2012 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -31,7 +31,7 @@
* \mainpage Track classes
*
* \section introduction Introduction
*
*
* \todo fill this out
*/
@@ -80,13 +80,6 @@ const Sint16 RESIZE_GRIP_WIDTH = 4;
const Uint16 TRACK_OP_BTN_WIDTH = 20;
const Uint16 TRACK_OP_BTN_HEIGHT = 14;
/*! The minimum track height in pixels
*
* Tracks can be resized by shift-dragging anywhere inside the track
* display. This sets the minimum size in pixels for a track.
*/
const Uint16 MINIMAL_TRACK_HEIGHT = 32;
/*! A pointer for that text bubble used when moving segments, etc.
*
@@ -644,7 +637,7 @@ void trackContentObjectView::mousePressEvent( QMouseEvent * _me )
* * If in move mode, move ourselves in the track,
* * or if in move-selection mode, move the entire selection,
* * or if in resize mode, resize ourselves,
* * otherwise ???
* * otherwise ???
*
* \param _me The QMouseEvent to handle.
* \todo what does the final else case do here?
@@ -1199,7 +1192,7 @@ void trackContentWidget::paintEvent( QPaintEvent * _pe )
// Don't draw background on BB-Editor
if( m_trackView->getTrackContainerView() != engine::getBBEditor() )
{
p.drawTiledPixmap( rect(), m_background, QPoint(
p.drawTiledPixmap( rect(), m_background, QPoint(
tcv->currentPosition().getTact() * ppt, 0 ) );
}
}
@@ -1563,6 +1556,7 @@ track::track( TrackTypes _type, trackContainer * _tc ) :
m_trackContentObjects() /*!< The track content objects (segments) */
{
m_trackContainer->addTrack( this );
m_height = -1;
}
@@ -1679,8 +1673,10 @@ void track::saveSettings( QDomDocument & _doc, QDomElement & _this )
_this.setAttribute( "type", type() );
_this.setAttribute( "name", name() );
_this.setAttribute( "muted", isMuted() );
// ### TODO
// _this.setAttribute( "height", m_trackView->height() );
if( m_height >= MINIMAL_TRACK_HEIGHT )
{
_this.setAttribute( "height", m_height );
}
QDomElement ts_de = _doc.createElement( nodeName() );
// let actual track (InstrumentTrack, bbTrack, sampleTrack etc.) save
@@ -1772,13 +1768,13 @@ void track::loadSettings( const QDomElement & _this )
}
}
node = node.nextSibling();
}
/*
if( _this.attribute( "height" ).toInt() >= MINIMAL_TRACK_HEIGHT )
}
if( _this.attribute( "height" ).toInt() >= MINIMAL_TRACK_HEIGHT &&
_this.attribute( "height" ).toInt() <= DEFAULT_TRACK_HEIGHT ) // workaround for #3585927, tobydox/2012-11-11
{
m_trackView->setFixedHeight(
_this.attribute( "height" ).toInt() );
}*/
m_height = _this.attribute( "height" ).toInt();
}
}
@@ -2122,6 +2118,7 @@ trackView::trackView( track * _track, trackContainerView * _tcv ) :
layout->addWidget( &m_trackOperationsWidget );
layout->addWidget( &m_trackSettingsWidget );
layout->addWidget( &m_trackContentWidget, 1 );
setFixedHeight( m_track->getHeight() );
resizeEvent( NULL );
@@ -2225,7 +2222,8 @@ void trackView::modelChanged()
connect( m_track, SIGNAL( destroyedTrack() ), this, SLOT( close() ) );
m_trackOperationsWidget.m_muteBtn->setModel( &m_track->m_mutedModel );
m_trackOperationsWidget.m_soloBtn->setModel( &m_track->m_soloModel );
ModelView::modelChanged();
ModelView::modelChanged();
setFixedHeight( m_track->getHeight() );
}
@@ -2256,6 +2254,10 @@ void trackView::undoStep( JournalEntry & _je )
MINIMAL_TRACK_HEIGHT ) );
m_trackContainerView->realignTracks();
break;
/*case RestoreTrack:
setFixedHeight( DEFAULT_TRACK_HEIGHT );
m_trackContainerView->realignTracks();
break; */
}
restoreJournallingState();
}
@@ -2331,6 +2333,16 @@ void trackView::dropEvent( QDropEvent * _de )
*/
void trackView::mousePressEvent( QMouseEvent * _me )
{
// If previously dragged too small, restore on shift-leftclick
if( height() < DEFAULT_TRACK_HEIGHT &&
_me->modifiers() & Qt::ShiftModifier &&
_me->button() == Qt::LeftButton )
{
setFixedHeight( DEFAULT_TRACK_HEIGHT );
m_track->setHeight( DEFAULT_TRACK_HEIGHT );
}
if( m_trackContainerView->allowRubberband() == true )
{
QWidget::mousePressEvent( _me );
@@ -2385,6 +2397,7 @@ void trackView::mousePressEvent( QMouseEvent * _me )
*/
void trackView::mouseMoveEvent( QMouseEvent * _me )
{
if( m_trackContainerView->allowRubberband() == true )
{
QWidget::mouseMoveEvent( _me );
@@ -2415,12 +2428,17 @@ void trackView::mouseMoveEvent( QMouseEvent * _me )
{
setFixedHeight( qMax<int>( _me->y(), MINIMAL_TRACK_HEIGHT ) );
m_trackContainerView->realignTracks();
m_track->setHeight( height() );
}
if( height() < DEFAULT_TRACK_HEIGHT )
{
toolTip::add( this, m_track->m_name );
}
}
/*! \brief Handle a mouse release event on this track View.
*
* \param _me the MouseEvent to handle.

View File

@@ -1,7 +1,7 @@
/*
* AutomatableModelView.cpp - implementation of AutomatableModelView
*
* Copyright (c) 2011 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2011-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -88,6 +88,12 @@ void AutomatableModelView::addDefaultActions( QMenu * _menu )
AutomatableModel::tr( "Edit song-global automation" ),
amvSlots,
SLOT( editSongGlobalAutomation() ) );
_menu->addAction( QPixmap(),
AutomatableModel::tr( "Remove song-global automation" ),
amvSlots,
SLOT( removeSongGlobalAutomation() ) );
_menu->addSeparator();
QString controllerTxt;
@@ -241,4 +247,11 @@ void AutomatableModelViewSlots::editSongGlobalAutomation()
void AutomatableModelViewSlots::removeSongGlobalAutomation()
{
delete AutomationPattern::globalAutomationPattern( amv->modelUntyped() );
}
#include "moc_AutomatableModelView.cxx"

View File

@@ -2,7 +2,7 @@
* AutomationEditor.cpp - implementation of AutomationEditor which is used for
* actual setting of dynamic values
*
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2008-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2006-2008 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
@@ -36,6 +36,8 @@
#include <QtGui/QScrollBar>
#include <QtGui/QStyleOption>
#include <QtGui/QWheelEvent>
#include <QToolTip>
#ifndef __USE_XOPEN
@@ -1256,6 +1258,10 @@ inline void AutomationEditor::drawCross( QPainter & _p )
_p.drawLine( VALUES_WIDTH, (int) cross_y, width(), (int) cross_y );
_p.drawLine( mouse_pos.x(), TOP_MARGIN, mouse_pos.x(),
height() - SCROLLBAR_SIZE );
QPoint tt_pos = QCursor::pos();
tt_pos.ry() -= 64;
tt_pos.rx() += 32;
QToolTip::showText( tt_pos,QString::number( level ),this);
}
@@ -1440,7 +1446,8 @@ void AutomationEditor::paintEvent( QPaintEvent * _pe )
timeMap & time_map = m_pattern->getTimeMap();
timeMap::iterator it = time_map.begin();
p.setPen( QColor( 0xFF, 0xDF, 0x20 ) );
do
while( it != time_map.end() )
{
Sint32 len_ticks = 4;
@@ -1532,7 +1539,7 @@ void AutomationEditor::paintEvent( QPaintEvent * _pe )
}
else printf("not in range\n");
++it;
} while( it != time_map.end() );
}
}
else
{

View File

@@ -427,7 +427,10 @@ void ControllerConnectionDialog::midiValueChanged()
if( m_midiAutoDetect.value() )
{
m_midiController->useDetected();
m_readablePorts->updateMenu();
if( m_readablePorts )
{
m_readablePorts->updateMenu();
}
}
}

View File

@@ -238,7 +238,7 @@ FxMixerView::FxMixerView() :
flags |= Qt::MSWindowsFixedSizeDialogHint;
flags &= ~Qt::WindowMaximizeButtonHint;
subWin->setWindowFlags( flags );
subWin->layout()->setSizeConstraint(QLayout::SetFixedSize);
//subWin->layout()->setSizeConstraint(QLayout::SetFixedSize);
parentWidget()->setAttribute( Qt::WA_DeleteOnClose, false );
parentWidget()->move( 5, 310 );

View File

@@ -1,9 +1,7 @@
#ifndef SINGLE_SOURCE_COMPILE
/*
* main_window.cpp - implementation of LMMS-main-window
*
* Copyright (c) 2004-2011 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -184,9 +182,12 @@ MainWindow::MainWindow( void ) :
m_updateTimer.start( 1000 / 20, this ); // 20 fps
// connect auto save
connect(&m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(autoSave()));
m_autoSaveTimer.start(1000 * 60); // 1 minute
if( configManager::inst()->value( "ui", "enableautosave" ).toInt() )
{
// connect auto save
connect(&m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(autoSave()));
m_autoSaveTimer.start(1000 * 60); // 1 minute
}
}
@@ -255,6 +256,12 @@ void MainWindow::finalize( void )
engine::getSong(),
SLOT( exportProject() ),
Qt::CTRL + Qt::Key_E );
project_menu->addAction( embed::getIconPixmap( "project_export" ),
tr( "E&xport tracks..." ),
engine::getSong(),
SLOT( exportProjectTracks() ),
Qt::CTRL + Qt::SHIFT + Qt::Key_E );
project_menu->addSeparator();
project_menu->addAction( embed::getIconPixmap( "exit" ), tr( "&Quit" ),
qApp, SLOT( closeAllWindows() ),
@@ -681,6 +688,9 @@ void MainWindow::openProject( void )
{
QFileDialog ofd( this, tr( "Open project" ), "",
tr( "MultiMedia Project (*.mmp *.mmpz *.xml)" ) );
#if QT_VERSION >= 0x040806
ofd.setOption( QFileDialog::DontUseCustomDirectoryIcons );
#endif
ofd.setDirectory( configManager::inst()->userProjectsDir() );
ofd.setFileMode( QFileDialog::ExistingFiles );
if( ofd.exec () == QDialog::Accepted &&
@@ -744,6 +754,9 @@ bool MainWindow::saveProjectAs( void )
QFileDialog sfd( this, tr( "Save project" ), "",
tr( "MultiMedia Project (*.mmp *.mmpz);;"
"MultiMedia Project Template (*.mpt)" ) );
#if QT_VERSION >= 0x040806
sfd.setOption( QFileDialog::DontUseCustomDirectoryIcons );
#endif
sfd.setAcceptMode( QFileDialog::AcceptSave );
sfd.setFileMode( QFileDialog::AnyFile );
QString f = engine::getSong()->projectFileName();
@@ -801,16 +814,17 @@ void MainWindow::help( void )
void MainWindow::toggleWindow( QWidget * _w )
void MainWindow::toggleWindow( QWidget *window, bool forceShow )
{
QWidget * parent = _w->parentWidget();
QWidget *parent = window->parentWidget();
if( m_workspace->activeSubWindow() != parent
|| parent->isHidden() )
if( forceShow ||
m_workspace->activeSubWindow() != parent ||
parent->isHidden() )
{
parent->show();
_w->show();
_w->setFocus();
window->show();
window->setFocus();
}
else
{
@@ -827,9 +841,9 @@ void MainWindow::toggleWindow( QWidget * _w )
void MainWindow::toggleBBEditorWin( void )
void MainWindow::toggleBBEditorWin( bool forceShow )
{
toggleWindow( engine::getBBEditor() );
toggleWindow( engine::getBBEditor(), forceShow );
}
@@ -1063,5 +1077,3 @@ void MainWindow::autoSave()
#include "moc_MainWindow.cxx"
#endif

View File

@@ -57,11 +57,6 @@
#include "templates.h"
#include "update_event.h"
#ifdef Q_WS_X11
#include <X11/Xlib.h>
#endif
/*! The black / white order of keys as they appear on the keyboard.
*/

View File

@@ -125,7 +125,7 @@
<item>
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Copyright (c) 2004-2012, LMMS developers</string>
<string>Copyright (c) 2004-2013, LMMS developers</string>
</property>
<property name="wordWrap" >
<bool>true</bool>

View File

@@ -279,6 +279,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="exportLoopCB">
<property name="text">
<string>Export as loop (remove end silence)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aliasFreeOscillatorsCB" >
<property name="text" >

View File

@@ -1,7 +1,7 @@
/*
* export_project_dialog.cpp - implementation of dialog for exporting project
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -23,20 +23,24 @@
*/
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtGui/QMessageBox>
#include "export_project_dialog.h"
#include "song.h"
#include "engine.h"
#include "MainWindow.h"
#include "ProjectRenderer.h"
#include "bb_track_container.h"
#include "bb_track.h"
exportProjectDialog::exportProjectDialog( const QString & _file_name,
QWidget * _parent ) :
QWidget * _parent, bool multi_export=false ) :
QDialog( _parent ),
Ui::ExportProjectDialog(),
m_fileName( _file_name ),
m_renderer( NULL )
m_fileExtension(),
m_multiExport(multi_export)
{
setupUi( this );
setWindowTitle( tr( "Export project to %1" ).arg(
@@ -83,7 +87,12 @@ exportProjectDialog::exportProjectDialog( const QString & _file_name,
exportProjectDialog::~exportProjectDialog()
{
delete m_renderer;
for( RenderVector::ConstIterator it = m_renderers.begin();
it != m_renderers.end(); ++it )
{
delete (*it);
}
}
@@ -91,13 +100,35 @@ exportProjectDialog::~exportProjectDialog()
void exportProjectDialog::reject()
{
if( m_renderer == NULL )
for( RenderVector::ConstIterator it = m_renderers.begin(); it != m_renderers.end(); ++it )
{
accept();
(*it)->abortProcessing();
}
QDialog::reject();
}
void exportProjectDialog::accept()
{
// If more to render, kick off next render job
if( m_renderers.isEmpty() == false )
{
popRender();
}
else
{
m_renderer->abortProcessing();
// If done, then reset mute states
while( m_unmuted.isEmpty() == false )
{
track* restoreTrack = m_unmuted.back();
m_unmuted.pop_back();
restoreTrack->setMuted( false );
}
QDialog::accept();
}
}
@@ -106,19 +137,154 @@ void exportProjectDialog::reject()
void exportProjectDialog::closeEvent( QCloseEvent * _ce )
{
if( m_renderer != NULL && m_renderer->isRunning() )
for( RenderVector::ConstIterator it = m_renderers.begin(); it != m_renderers.end(); ++it )
{
m_renderer->abortProcessing();
if( (*it)->isRunning() )
{
(*it)->abortProcessing();
}
}
QDialog::closeEvent( _ce );
}
void exportProjectDialog::popRender()
{
if( m_multiExport && m_tracksToRender.isEmpty() == false )
{
track* renderTrack = m_tracksToRender.back();
m_tracksToRender.pop_back();
// Set must states for song tracks
for( TrackVector::ConstIterator it = m_unmuted.begin(); it != m_unmuted.end(); ++it )
{
if( (*it) == renderTrack )
{
(*it)->setMuted( false );
}
else
{
(*it)->setMuted( true );
}
}
}
// Pop next render job and start
ProjectRenderer* r = m_renderers.back();
m_renderers.pop_back();
render( r );
}
void exportProjectDialog::multiRender()
{
m_dirName = m_fileName;
QString path = QDir(m_fileName).filePath("text.txt");
int x = 1;
const trackContainer::trackList & tl = engine::getSong()->tracks();
// Check for all unmuted tracks. Remember list.
for( trackContainer::trackList::ConstIterator it = tl.begin();
it != tl.end(); ++it )
{
track* tk = (*it);
track::TrackTypes type = tk->type();
// Don't mute automation tracks
if ( tk->isMuted() == false &&
( type == track::InstrumentTrack || type == track::SampleTrack ) )
{
m_unmuted.push_back(tk);
QString nextName = tk->name();
nextName = nextName.remove(QRegExp("[^a-zA-Z]"));
QString name = QString( "%1_%2%3" ).arg( x++ ).arg( nextName ).arg( m_fileExtension );
m_fileName = QDir(m_dirName).filePath(name);
prepRender();
}
else if (! tk->isMuted() && type == track::BBTrack )
{
m_unmutedBB.push_back(tk);
}
}
const trackContainer::trackList t2 = engine::getBBTrackContainer()->tracks();
for( trackContainer::trackList::ConstIterator it = t2.begin(); it != t2.end(); ++it )
{
track* tk = (*it);
if ( tk->isMuted() == false )
{
m_unmuted.push_back(tk);
QString nextName = tk->name();
nextName = nextName.remove(QRegExp("[^a-zA-Z]"));
QString name = QString( "%1_%2%3" ).arg( x++ ).arg( nextName ).arg( m_fileExtension );
m_fileName = QDir(m_dirName).filePath(name);
prepRender();
}
}
m_tracksToRender = m_unmuted;
popRender();
}
ProjectRenderer* exportProjectDialog::prepRender()
{
mixer::qualitySettings qs =
mixer::qualitySettings(
static_cast<mixer::qualitySettings::Interpolation>(interpolationCB->currentIndex()),
static_cast<mixer::qualitySettings::Oversampling>(oversamplingCB->currentIndex()),
sampleExactControllersCB->isChecked(),
aliasFreeOscillatorsCB->isChecked() );
ProjectRenderer::OutputSettings os = ProjectRenderer::OutputSettings(
samplerateCB->currentText().section(" ", 0, 0).toUInt(),
false,
bitrateCB->currentText().section(" ", 0, 0).toUInt(),
static_cast<ProjectRenderer::Depths>( depthCB->currentIndex() ) );
engine::getSong()->setExportLoop( exportLoopCB->isChecked() );
ProjectRenderer* renderer = new ProjectRenderer( qs, os, m_ft, m_fileName );
m_renderers.push_back(renderer);
return renderer;
}
void exportProjectDialog::render( ProjectRenderer* renderer )
{
if( renderer->isReady() )
{
connect( renderer, SIGNAL( progressChanged( int ) ), progressBar, SLOT( setValue( int ) ) );
connect( renderer, SIGNAL( progressChanged( int ) ), this, SLOT( updateTitleBar( int ) )) ;
connect( renderer, SIGNAL( finished() ), this, SLOT( accept() ) );
connect( renderer, SIGNAL( finished() ), engine::mainWindow(), SLOT( resetWindowTitle() ) );
renderer->startProcessing();
}
else
{
accept();
}
}
void exportProjectDialog::startBtnClicked()
{
ProjectRenderer::ExportFileFormats ft = ProjectRenderer::NumFileFormats;
m_ft = ProjectRenderer::NumFileFormats;
for( int i = 0; i < ProjectRenderer::NumFileFormats; ++i )
{
@@ -126,12 +292,13 @@ void exportProjectDialog::startBtnClicked()
ProjectRenderer::tr(
__fileEncodeDevices[i].m_description ) )
{
ft = __fileEncodeDevices[i].m_fileFormat;
m_ft = __fileEncodeDevices[i].m_fileFormat;
m_fileExtension = QString( QLatin1String( __fileEncodeDevices[i].m_extension ) );
break;
}
}
if( ft == ProjectRenderer::NumFileFormats )
if( m_ft == ProjectRenderer::NumFileFormats )
{
QMessageBox::information( this, tr( "Error" ),
tr( "Error while determining file-encoder device. "
@@ -146,38 +313,14 @@ void exportProjectDialog::startBtnClicked()
updateTitleBar( 0 );
mixer::qualitySettings qs = mixer::qualitySettings(
static_cast<mixer::qualitySettings::Interpolation>(
interpolationCB->currentIndex() ),
static_cast<mixer::qualitySettings::Oversampling>(
oversamplingCB->currentIndex() ),
sampleExactControllersCB->isChecked(),
aliasFreeOscillatorsCB->isChecked() );
ProjectRenderer::OutputSettings os = ProjectRenderer::OutputSettings(
samplerateCB->currentText().section( " ", 0, 0 ).toUInt(),
false,
bitrateCB->currentText().section( " ", 0, 0 ).toUInt(),
static_cast<ProjectRenderer::Depths>(
depthCB->currentIndex() ) );
m_renderer = new ProjectRenderer( qs, os, ft, m_fileName );
if( m_renderer->isReady() )
if (m_multiExport==true)
{
connect( m_renderer, SIGNAL( progressChanged( int ) ),
progressBar, SLOT( setValue( int ) ) );
connect( m_renderer, SIGNAL( progressChanged( int ) ),
this, SLOT( updateTitleBar( int ) ) );
connect( m_renderer, SIGNAL( finished() ),
this, SLOT( accept() ) );
connect( m_renderer, SIGNAL( finished() ),
engine::mainWindow(), SLOT( resetWindowTitle() ) );
m_renderer->startProcessing();
multiRender();
}
else
{
accept();
prepRender();
popRender();
}
}

View File

@@ -667,11 +667,12 @@ void pianoRoll::markSemiTone( int i )
const int first = chord->isScale() ? 0 : key;
const int last = chord->isScale() ? NumKeys : key + chord->last();
const int cap = chord->isScale() ? KeysPerOctave : chord->last();
const int cap = ( chord->isScale() || chord->last() == 0 ) ? KeysPerOctave : chord->last();
for( int i = first; i <= last; i++ )
{
if( chord->hasSemiTone( std::abs( key - i ) % cap ) )
//if( chord->hasSemiTone( std::abs( key - i ) % cap ) )
if( chord->hasSemiTone( ( i + cap - ( key % cap ) ) % cap ) )
{
m_markedSemiTones.push_back( i );
}
@@ -2689,6 +2690,24 @@ void pianoRoll::paintEvent( QPaintEvent * _pe )
int key = m_startKey;
// display note marks before drawing other lines
for( int i = 0; i < m_markedSemiTones.size(); i++ )
{
const int key_num = m_markedSemiTones.at( i );
const int y = keyAreaBottom() + 5
- KEY_LINE_HEIGHT * ( key_num - m_startKey + 1 );
if( y > keyAreaBottom() )
{
break;
}
p.fillRect( WHITE_KEY_WIDTH+1, y-KEY_LINE_HEIGHT/2,
width() - 10, KEY_LINE_HEIGHT,
QColor( 0, 80 - ( key_num % KeysPerOctave ) * 3, 64 + key_num / 2) );
}
// draw all white keys...
for( int y = key_line_y + 1 + y_offset; y > PR_TOP_MARGIN;
key_line_y -= KEY_LINE_HEIGHT, ++keys_processed )
@@ -2817,22 +2836,6 @@ void pianoRoll::paintEvent( QPaintEvent * _pe )
++key;
}
// display note marks
for( int i = 0; i < m_markedSemiTones.size(); i++ )
{
const int key_num = m_markedSemiTones.at( i );
const int y = keyAreaBottom() + 5
- KEY_LINE_HEIGHT * ( key_num - m_startKey + 1 );
if( y > keyAreaBottom() )
{
break;
}
p.fillRect( WHITE_KEY_WIDTH, y,
width() - 10, 1,
QColor( 64, 64 + ( key_num % KeysPerOctave ) * 7, 96 + key_num ) );
}
// erase the area below the piano, because there might be keys that
// should be only half-visible

View File

@@ -1,7 +1,7 @@
/*
* setup_dialog.cpp - dialog for setting up LMMS
*
* Copyright (c) 2005-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2005-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -113,10 +113,15 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) :
m_manualChPiano( configManager::inst()->value( "ui",
"manualchannelpiano" ).toInt() ),
m_smoothScroll( configManager::inst()->value( "ui", "smoothscroll" ).toInt() ),
m_enableAutoSave( configManager::inst()->value( "ui", "enableautosave" ).toInt() ),
m_oneInstrumentTrackWindow( configManager::inst()->value( "ui",
"oneinstrumenttrackwindow" ).toInt() ),
m_compactTrackButtons( configManager::inst()->value( "ui",
"compacttrackbuttons" ).toInt() )
"compacttrackbuttons" ).toInt() ),
m_syncVSTPlugins( configManager::inst()->value( "ui",
"syncvstplugins" ).toInt() ),
m_animateAFP(configManager::inst()->value( "ui",
"animateafp").toInt() )
{
setWindowIcon( embed::getIconPixmap( "setup_general" ) );
setWindowTitle( tr( "Setup LMMS" ) );
@@ -185,7 +190,7 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) :
tabWidget * misc_tw = new tabWidget( tr( "MISC" ), general );
misc_tw->setFixedHeight( 156 );
misc_tw->setFixedHeight( 174 );
ledCheckBox * enable_tooltips = new ledCheckBox(
tr( "Enable tooltips" ),
@@ -246,6 +251,15 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) :
this, SLOT( toggleCompactTrackButtons( bool ) ) );
ledCheckBox * syncVST = new ledCheckBox(
tr( "Sync VST plugins to host playback" ),
misc_tw );
syncVST->move( 10, 144 );
syncVST->setChecked( m_syncVSTPlugins );
connect( syncVST, SIGNAL( toggled( bool ) ),
this, SLOT( toggleSyncVSTPlugins( bool ) ) );
gen_layout->addWidget( bufsize_tw );
gen_layout->addSpacing( 10 );
@@ -464,7 +478,7 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) :
tabWidget * ui_fx_tw = new tabWidget( tr( "UI effects vs. "
"performance" ).toUpper(),
performance );
ui_fx_tw->setFixedHeight( 90 );
ui_fx_tw->setFixedHeight( 120 );
ledCheckBox * disable_ch_act_ind = new ledCheckBox(
tr( "Disable channel activity indicators" ),
@@ -491,6 +505,23 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) :
this, SLOT( toggleSmoothScroll( bool ) ) );
ledCheckBox * autoSave = new ledCheckBox(
tr( "Enable auto save feature" ), ui_fx_tw );
autoSave->move( 10, 80 );
autoSave->setChecked( m_enableAutoSave );
connect( autoSave, SIGNAL( toggled( bool ) ),
this, SLOT( toggleAutoSave( bool ) ) );
ledCheckBox * animAFP = new ledCheckBox(
tr( "Show playback cursor in AudioFileProcessor" ),
ui_fx_tw );
animAFP->move( 10, 100 );
animAFP->setChecked( m_animateAFP );
connect( animAFP, SIGNAL( toggled( bool ) ),
this, SLOT( toggleAnimateAFP( bool ) ) );
perf_layout->addWidget( ui_fx_tw );
perf_layout->addStretch();
@@ -759,10 +790,17 @@ void setupDialog::accept()
QString::number( m_manualChPiano ) );
configManager::inst()->setValue( "ui", "smoothscroll",
QString::number( m_smoothScroll ) );
configManager::inst()->setValue( "ui", "enableautosave",
QString::number( m_enableAutoSave ) );
configManager::inst()->setValue( "ui", "oneinstrumenttrackwindow",
QString::number( m_oneInstrumentTrackWindow ) );
configManager::inst()->setValue( "ui", "compacttrackbuttons",
QString::number( m_compactTrackButtons ) );
configManager::inst()->setValue( "ui", "syncvstplugins",
QString::number( m_syncVSTPlugins ) );
configManager::inst()->setValue( "ui", "animateafp",
QString::number( m_animateAFP ) );
configManager::inst()->setWorkingDir( m_workingDir );
configManager::inst()->setVSTDir( m_vstDir );
@@ -926,6 +964,14 @@ void setupDialog::toggleSmoothScroll( bool _enabled )
void setupDialog::toggleAutoSave( bool _enabled )
{
m_enableAutoSave = _enabled;
}
void setupDialog::toggleCompactTrackButtons( bool _enabled )
@@ -937,6 +983,20 @@ void setupDialog::toggleCompactTrackButtons( bool _enabled )
void setupDialog::toggleSyncVSTPlugins( bool _enabled )
{
m_syncVSTPlugins = _enabled;
}
void setupDialog::toggleAnimateAFP( bool _enabled )
{
m_animateAFP = _enabled;
}
void setupDialog::toggleOneInstrumentTrackWindow( bool _enabled )
{
m_oneInstrumentTrackWindow = _enabled;
@@ -950,7 +1010,11 @@ void setupDialog::openWorkingDir()
{
QString new_dir = QFileDialog::getExistingDirectory( this,
tr( "Choose LMMS working directory" ),
m_workingDir );
m_workingDir
#if QT_VERSION >= 0x040806
, QFileDialog::DontUseCustomDirectoryIcons
#endif
);
if( new_dir != QString::null )
{
m_wdLineEdit->setText( new_dir );

View File

@@ -1,7 +1,7 @@
/*
* song_editor.cpp - basic window for song-editing
*
* Copyright (c) 2004-2011 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -50,6 +50,7 @@
#include "tool_button.h"
#include "tooltip.h"
#include "visualization_widget.h"
#include "TimeDisplayWidget.h"
#include "AudioDevice.h"
#include "piano_roll.h"
#include "config_mgr.h"
@@ -130,7 +131,7 @@ songEditor::songEditor( song * _song, songEditor * & _engine_ptr ) :
"should be played within a minute (or how many measures "
"should be played within four minutes)." ) );
engine::mainWindow()->addWidgetToToolBar( m_tempoSpinBox, 0 );
int tempoSpinBoxCol = engine::mainWindow()->addWidgetToToolBar( m_tempoSpinBox, 0 );
#if 0
toolButton * hq_btn = new toolButton( embed::getIconPixmap( "hq_mode" ),
@@ -145,6 +146,9 @@ songEditor::songEditor( song * _song, songEditor * & _engine_ptr ) :
engine::mainWindow()->addSpacingToToolBar( 10 );
engine::mainWindow()->addWidgetToToolBar( new TimeDisplayWidget, 1, tempoSpinBoxCol );
engine::mainWindow()->addSpacingToToolBar( 10 );
m_timeSigDisplay = new MeterDialog( this, TRUE );
m_timeSigDisplay->setModel( &m_s->m_timeSigModel );

View File

@@ -175,29 +175,36 @@ void EffectRackView::update()
Qt::QueuedConnection );
view->show();
m_effectViews.append( view );
view_map[i] = true;
if( i < view_map.size() )
{
view_map[i] = true;
}
else
{
view_map.append( true );
}
}
}
int i = m_lastY = 0;
int i = m_lastY = 0, nView = 0;
for( QVector<EffectView *>::Iterator it = m_effectViews.begin();
it != m_effectViews.end(); )
it != m_effectViews.end(); i++ )
{
if( i < view_map.size() && i < m_effectViews.size() &&
view_map[i] == false )
if( i < view_map.size() && view_map[i] == false )
{
delete m_effectViews[i];
delete m_effectViews[nView];
it = m_effectViews.erase( it );
}
else
{
( *it )->move( 0, m_lastY );
m_lastY += ( *it )->height();
++nView;
++it;
++i;
}
}
w->setFixedSize( 210, m_lastY );
QWidget::update();
@@ -242,7 +249,7 @@ void EffectRackView::addEffect()
void EffectRackView::modelChanged()
{
clearViews();
//clearViews();
m_effectsGroupBox->setModel( &fxChain()->m_enabledModel );
connect( fxChain(), SIGNAL( aboutToClear() ),
this, SLOT( clearViews() ) );

View File

@@ -85,6 +85,8 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
"while deciding when to stop processing signals." ) );
setModel( _model );
if( effect()->controls()->controlCount() > 0 )
{
QPushButton * ctls_btn = new QPushButton( tr( "Controls" ),
@@ -94,6 +96,7 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
ctls_btn->setGeometry( 140, 14, 50, 20 );
connect( ctls_btn, SIGNAL( clicked() ),
this, SLOT( editControls() ) );
m_controlView = effect()->controls()->createView();
if( m_controlView )
{
@@ -141,7 +144,8 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
"Right clicking will bring up a context menu where you can change the order "
"in which the effects are processed or delete an effect altogether." ) );
setModel( _model );
//move above vst effect view creation
//setModel( _model );
}
@@ -149,7 +153,15 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
EffectView::~EffectView()
{
#ifdef LMMS_BUILD_LINUX
delete m_subWindow;
#else
// otherwise on win32 build VST GUI can get lost
m_subWindow->hide();
#endif
}
@@ -159,7 +171,7 @@ void EffectView::editControls()
{
if( m_subWindow )
{
if( !effect()->controls()->isViewVisible() )
if( !m_subWindow->isVisible() )
{
m_subWindow->show();
m_subWindow->raise();

View File

@@ -2,7 +2,7 @@
* EnvelopeAndLfoView.cpp - widget which is m_used by envelope/lfo/filter-
* tab of instrument track window
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -341,25 +341,25 @@ void EnvelopeAndLfoView::mousePressEvent( QMouseEvent * _me )
if( QRect( ENV_GRAPH_X, ENV_GRAPH_Y, s_envGraph->width(),
s_envGraph->height() ).contains( _me->pos() ) == true )
{
if( m_amountKnob->value<float>() < 1.0f )
if( m_params->m_amountModel.value() < 1.0f )
{
m_amountKnob->setValue( 1.0f );
m_params->m_amountModel.setValue( 1.0f );
}
else
{
m_amountKnob->setValue( 0.0f );
m_params->m_amountModel.setValue( 0.0f );
}
}
else if( QRect( LFO_GRAPH_X, LFO_GRAPH_Y, s_lfoGraph->width(),
s_lfoGraph->height() ).contains( _me->pos() ) == true )
{
if( m_lfoAmountKnob->value<float>() < 1.0f )
if( m_params->m_lfoAmountModel.value() < 1.0f )
{
m_lfoAmountKnob->setValue( 1.0f );
m_params->m_lfoAmountModel.setValue( 1.0f );
}
else
{
m_lfoAmountKnob->setValue( 0.0f );
m_params->m_lfoAmountModel.setValue( 0.0f );
}
}
}

View File

@@ -47,8 +47,8 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget * _parent ) :
m_midiInputGroupBox = new groupBox( tr( "ENABLE MIDI INPUT" ), this );
m_midiInputGroupBox->setGeometry( 4, 5, 242, 80 );
m_inputChannelSpinBox = new lcdSpinBox( 3, m_midiInputGroupBox );
m_inputChannelSpinBox->addTextForValue( 0, "---" );
m_inputChannelSpinBox = new lcdSpinBox( 2, m_midiInputGroupBox );
m_inputChannelSpinBox->addTextForValue( 0, "--" );
m_inputChannelSpinBox->setLabel( tr( "CHANNEL" ) );
m_inputChannelSpinBox->move( 16, 32 );
m_inputChannelSpinBox->setEnabled( false );
@@ -69,7 +69,7 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget * _parent ) :
m_midiOutputGroupBox = new groupBox( tr( "ENABLE MIDI OUTPUT" ), this );
m_midiOutputGroupBox->setGeometry( 4, 90, 242, 80 );
m_outputChannelSpinBox = new lcdSpinBox( 3, m_midiOutputGroupBox );
m_outputChannelSpinBox = new lcdSpinBox( 2, m_midiOutputGroupBox );
m_outputChannelSpinBox->setLabel( tr( "CHANNEL" ) );
m_outputChannelSpinBox->move( 16, 32 );
m_outputChannelSpinBox->setEnabled( false );
@@ -85,26 +85,34 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget * _parent ) :
m_outputProgramSpinBox->move( 112, 32 );
m_outputProgramSpinBox->setEnabled( false );
m_fixedOutputNoteSpinBox = new lcdSpinBox( 3, m_midiOutputGroupBox );
m_fixedOutputNoteSpinBox->addTextForValue( -1, "---" );
m_fixedOutputNoteSpinBox->setLabel( tr( "NOTE" ) );
m_fixedOutputNoteSpinBox->move( 160, 32 );
m_fixedOutputNoteSpinBox->setEnabled( false );
connect( m_midiOutputGroupBox->ledButton(), SIGNAL( toggled( bool ) ),
m_outputChannelSpinBox, SLOT( setEnabled( bool ) ) );
connect( m_midiOutputGroupBox->ledButton(), SIGNAL( toggled( bool ) ),
m_fixedOutputVelocitySpinBox, SLOT( setEnabled( bool ) ) );
connect( m_midiOutputGroupBox->ledButton(), SIGNAL( toggled( bool ) ),
m_outputProgramSpinBox, SLOT( setEnabled( bool ) ) );
connect( m_midiOutputGroupBox->ledButton(), SIGNAL( toggled( bool ) ),
m_fixedOutputNoteSpinBox, SLOT( setEnabled( bool ) ) );
if( !engine::getMixer()->midiClient()->isRaw() )
{
m_rpBtn = new QToolButton( m_midiInputGroupBox );
m_rpBtn->setText( tr( "MIDI devices to receive MIDI events from" ) );
m_rpBtn->setIcon( embed::getIconPixmap( "piano" ) );
m_rpBtn->setGeometry( 186, 24, 32, 32 );
m_rpBtn->setGeometry( 208, 24, 32, 32 );
m_rpBtn->setPopupMode( QToolButton::InstantPopup );
m_wpBtn = new QToolButton( m_midiOutputGroupBox );
m_wpBtn->setText( tr( "MIDI devices to send MIDI events to" ) );
m_wpBtn->setIcon( embed::getIconPixmap( "piano" ) );
m_wpBtn->setGeometry( 186, 24, 32, 32 );
m_wpBtn->setGeometry( 208, 24, 32, 32 );
m_wpBtn->setPopupMode( QToolButton::InstantPopup );
}
}
@@ -131,6 +139,8 @@ void InstrumentMidiIOView::modelChanged()
m_outputChannelSpinBox->setModel( &mp->m_outputChannelModel );
m_fixedOutputVelocitySpinBox->setModel(
&mp->m_fixedOutputVelocityModel );
m_fixedOutputNoteSpinBox->setModel(
&mp->m_fixedOutputNoteModel );
m_outputProgramSpinBox->setModel( &mp->m_outputProgramModel );
if( m_rpBtn )

View File

@@ -0,0 +1,246 @@
/*
* LcdWidget.cpp - a widget for displaying numbers in LCD style
*
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2008 Paul Giblock <pgllama/at/gmail.com>
*
* 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include <QtGui/QApplication>
#include <QtGui/QLabel>
#include <QtGui/QMouseEvent>
#include <QtGui/QPainter>
#include <QtGui/QFontMetrics>
#include <QtGui/QStyleOptionFrameV2>
#include "LcdWidget.h"
#include "engine.h"
#include "embed.h"
#include "gui_templates.h"
#include "MainWindow.h"
LcdWidget::LcdWidget( int numDigits, QWidget* parent, const QString& name ) :
QWidget( parent ),
m_label(),
m_numDigits( numDigits )
{
setEnabled( true );
setWindowTitle( name );
m_lcdPixmap = new QPixmap( embed::getIconPixmap( "lcd_19green" ) );
m_cellWidth = m_lcdPixmap->size().width() / LcdWidget::charsPerPixmap;
m_cellHeight = m_lcdPixmap->size().height() / 2;
m_marginWidth = m_cellWidth / 2;
updateSize();
}
LcdWidget::LcdWidget( int numDigits, const QString& style, QWidget* parent, const QString& name ) :
QWidget( parent ),
m_label(),
m_numDigits( numDigits )
{
setEnabled( true );
setWindowTitle( name );
// We should make a factory for these or something.
m_lcdPixmap = new QPixmap( embed::getIconPixmap( QString( "lcd_" + style ).toUtf8().constData() ) );
m_cellWidth = m_lcdPixmap->size().width() / LcdWidget::charsPerPixmap;
m_cellHeight = m_lcdPixmap->size().height() / 2;
m_marginWidth = m_cellWidth / 2;
updateSize();
}
LcdWidget::~LcdWidget()
{
delete m_lcdPixmap;
}
void LcdWidget::setValue( int value )
{
QString s = m_textForValue[value];
if( s.isEmpty() )
{
s = QString::number( value );
// TODO: if pad == true
/*
while( (int) s.length() < m_numDigits )
{
s = "0" + s;
}
*/
}
m_display = s;
update();
}
void LcdWidget::paintEvent( QPaintEvent* )
{
QPainter p( this );
QSize cellSize( m_cellWidth, m_cellHeight );
QRect cellRect( 0, 0, m_cellWidth, m_cellHeight );
int margin = 1; // QStyle::PM_DefaultFrameWidth;
//int lcdWidth = m_cellWidth * m_numDigits + (margin*m_marginWidth)*2;
// p.translate( width() / 2 - lcdWidth / 2, 0 );
p.save();
p.translate( margin, margin );
// Left Margin
p.drawPixmap( cellRect, *m_lcdPixmap,
QRect( QPoint( charsPerPixmap*m_cellWidth,
isEnabled()?0:m_cellHeight ),
cellSize ) );
p.translate( m_marginWidth, 0 );
// Padding
for( int i=0; i < m_numDigits - m_display.length(); i++ )
{
p.drawPixmap( cellRect, *m_lcdPixmap,
QRect( QPoint( 10 * m_cellWidth, isEnabled()?0:m_cellHeight) , cellSize ) );
p.translate( m_cellWidth, 0 );
}
// Digits
for( int i=0; i < m_display.length(); i++ )
{
int val = m_display[i].digitValue();
if( val < 0 )
{
if( m_display[i] == '-' )
val = 11;
else
val = 10;
}
p.drawPixmap( cellRect, *m_lcdPixmap,
QRect( QPoint( val*m_cellWidth,
isEnabled()?0:m_cellHeight ),
cellSize ) );
p.translate( m_cellWidth, 0 );
}
// Right Margin
p.drawPixmap( QRect( 0, 0, m_marginWidth-1, m_cellHeight ), *m_lcdPixmap,
QRect( charsPerPixmap*m_cellWidth, isEnabled()?0:m_cellHeight,
m_cellWidth / 2, m_cellHeight ) );
p.restore();
// Border
QStyleOptionFrame opt;
opt.initFrom( this );
opt.state = QStyle::State_Sunken;
opt.rect = QRect( 0, 0, m_cellWidth * m_numDigits + (margin+m_marginWidth)*2 - 1,
m_cellHeight + (margin*2) );
style()->drawPrimitive( QStyle::PE_Frame, &opt, &p, this );
p.resetTransform();
// Label
if( !m_label.isEmpty() )
{
p.setFont( pointSize<6>( p.font() ) );
p.setPen( QColor( 64, 64, 64 ) );
p.drawText( width() / 2 -
p.fontMetrics().width( m_label ) / 2 + 1,
height(), m_label );
p.setPen( QColor( 255, 255, 255 ) );
p.drawText( width() / 2 -
p.fontMetrics().width( m_label ) / 2,
height() - 1, m_label );
}
}
void LcdWidget::setLabel( const QString & _txt )
{
m_label = _txt;
updateSize();
}
void LcdWidget::setMarginWidth( int _width )
{
m_marginWidth = _width;
updateSize();
}
void LcdWidget::updateSize()
{
int margin = 1;
if (m_label.isEmpty()) {
setFixedSize( m_cellWidth * m_numDigits + 2*(margin+m_marginWidth),
m_cellHeight + (2*margin) );
}
else {
setFixedSize( qMax<int>(
m_cellWidth * m_numDigits + 2*(margin+m_marginWidth),
QFontMetrics( pointSize<6>( font() ) ).width( m_label ) ),
m_cellHeight + (2*margin) + 8 );
}
update();
}
#include "moc_LcdWidget.cxx"

View File

@@ -0,0 +1,139 @@
/*
* TimeDisplayWidget.cpp - widget for displaying current playback time
*
* Copyright (c) 2014 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include <QtGui/QMouseEvent>
#include "TimeDisplayWidget.h"
#include "MainWindow.h"
#include "engine.h"
#include "tooltip.h"
#include "song.h"
TimeDisplayWidget::TimeDisplayWidget() :
QWidget(),
m_displayMode( MinutesSeconds ),
m_spinBoxesLayout( this ),
m_majorLCD( 2, this ),
m_minorLCD( 2, this ),
m_milliSecondsLCD( 3, this )
{
m_spinBoxesLayout.setSpacing( 0 );
m_spinBoxesLayout.setMargin( 0 );
m_spinBoxesLayout.addWidget( &m_majorLCD );
m_spinBoxesLayout.addWidget( &m_minorLCD );
m_spinBoxesLayout.addWidget( &m_milliSecondsLCD );
setMaximumHeight( 32 );
toolTip::add( this, tr( "click to change time units" ) );
// update labels of LCD spinboxes
setDisplayMode( m_displayMode );
connect( engine::mainWindow(), SIGNAL( periodicUpdate() ),
this, SLOT( updateTime() ) );
}
TimeDisplayWidget::~TimeDisplayWidget()
{
}
void TimeDisplayWidget::setDisplayMode( DisplayMode displayMode )
{
m_displayMode = displayMode;
m_milliSecondsLCD.setLabel( "MSEC" );
switch( m_displayMode )
{
case MinutesSeconds:
m_majorLCD.setLabel( "MIN" );
m_minorLCD.setLabel( "SEC" );
break;
case BarsTicks:
m_majorLCD.setLabel( "BAR" );
m_minorLCD.setLabel( "TICK" );
break;
default: break;
}
}
void TimeDisplayWidget::updateTime()
{
song* s = engine::getSong();
switch( m_displayMode )
{
case MinutesSeconds:
m_majorLCD.setValue( s->getMilliseconds() / 60000 );
m_minorLCD.setValue( ( s->getMilliseconds() / 1000 ) % 60 );
break;
case BarsTicks:
m_majorLCD.setValue( s->getTacts() );
m_minorLCD.setValue( ( s->getTicks() % s->ticksPerTact() ) / 3 );
break;
default: break;
}
m_milliSecondsLCD.setValue( s->getMilliseconds() % 1000 );
}
void TimeDisplayWidget::mousePressEvent( QMouseEvent* mouseEvent )
{
if( mouseEvent->button() == Qt::LeftButton )
{
if( m_displayMode == MinutesSeconds )
{
setDisplayMode( BarsTicks );
}
else
{
setDisplayMode( MinutesSeconds );
}
}
}
#include "moc_TimeDisplayWidget.cxx"

View File

@@ -1,8 +1,8 @@
/*
* fader.cpp - fader-widget used in mixer - partly taken from Hydrogen
*
* Copyright (c) 2008-2011 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* Copyright (c) 2008-2012 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
@@ -45,6 +45,7 @@
*/
#include <QtGui/QInputDialog>
#include <QtGui/QMouseEvent>
#include <QtGui/QPaintEvent>
#include <QtGui/QPainter>
@@ -73,7 +74,9 @@ fader::fader( FloatModel * _model, const QString & _name, QWidget * _parent ) :
m_fMaxPeak( 1.1 ),
m_back( embed::getIconPixmap( "fader_background" ) ),
m_leds( embed::getIconPixmap( "fader_leds" ) ),
m_knob( embed::getIconPixmap( "fader_knob" ) )
m_knob( embed::getIconPixmap( "fader_knob" ) ),
m_moveStartPoint( -1 ),
m_startValue( 0 )
{
if( s_textFloat == NULL )
{
@@ -107,35 +110,67 @@ void fader::contextMenuEvent( QContextMenuEvent * _ev )
void fader::mouseMoveEvent( QMouseEvent *ev )
void fader::mouseMoveEvent( QMouseEvent *mouseEvent )
{
float fVal = (float)( height() - ev->y() ) / (float)height();
fVal = fVal * ( m_model->maxValue() - m_model->minValue() );
if( m_moveStartPoint >= 0 )
{
int dy = m_moveStartPoint - mouseEvent->globalY();
fVal = fVal + m_model->minValue();
float delta = dy * ( m_model->maxValue() - m_model->minValue() ) / (float) ( height() - m_knob.height() );
m_model->setValue( fVal );
model()->setValue( m_startValue + delta );
updateTextFloat();
updateTextFloat();
}
}
void fader::mousePressEvent( QMouseEvent * _me )
void fader::mousePressEvent( QMouseEvent* mouseEvent )
{
if( _me->button() == Qt::LeftButton &&
! ( _me->modifiers() & Qt::ControlModifier ) )
if( mouseEvent->button() == Qt::LeftButton &&
! ( mouseEvent->modifiers() & Qt::ControlModifier ) )
{
updateTextFloat();
s_textFloat->show();
if( mouseEvent->y() >= knobPosY() - m_knob.height() && mouseEvent->y() < knobPosY() )
{
updateTextFloat();
s_textFloat->show();
mouseMoveEvent( _me );
_me->accept();
m_moveStartPoint = mouseEvent->globalY();
m_startValue = model()->value();
mouseEvent->accept();
}
else
{
m_moveStartPoint = -1;
}
}
else
{
AutomatableModelView::mousePressEvent( _me );
AutomatableModelView::mousePressEvent( mouseEvent );
}
}
void fader::mouseDoubleClickEvent( QMouseEvent* mouseEvent )
{
bool ok;
// TODO: dbV handling
int newValue = QInputDialog::getInteger( this, windowTitle(),
tr( "Please enter a new value between %1 and %2:" ).
arg( model()->minValue()*100 ).
arg( model()->maxValue()*100 ),
model()->value()*100,
model()->minValue()*100,
model()->maxValue()*100, 1, &ok );
if( ok )
{
model()->setValue( newValue / 100.0f );
}
}
@@ -153,11 +188,11 @@ void fader::wheelEvent ( QWheelEvent *ev )
if ( ev->delta() > 0 )
{
m_model->incValue( 5 );
m_model->incValue( 1 );
}
else
{
m_model->incValue( -5 );
m_model->incValue( -1 );
}
updateTextFloat();
s_textFloat->setVisibilityTimeOut( 1000 );
@@ -225,7 +260,7 @@ void fader::updateTextFloat()
{
s_textFloat->setText( QString("Volume: %1 %").arg( m_model->value() * 100 ) );
}
s_textFloat->moveGlobal( this, QPoint( width() - m_knob.width() - 5, knob_y() - 46 ) );
s_textFloat->moveGlobal( this, QPoint( width() - m_knob.width() - 5, knobPosY() - 46 ) );
}
@@ -268,18 +303,7 @@ void fader::paintEvent( QPaintEvent * ev)
}
// knob
static const uint knob_height = 29;
static const uint knob_width = 15;
float fRange = m_model->maxValue() - m_model->minValue();
float realVal = m_model->value() - m_model->minValue();
// uint knob_y = (uint)( 116.0 - ( 86.0 * ( m_model->value() / fRange ) ) );
uint knob_y = (uint)( 116.0 - ( 86.0 * ( realVal / fRange ) ) );
painter.drawPixmap( QRect( 4, knob_y - knob_height, knob_width, knob_height), m_knob, QRect( 0, 0, knob_width, knob_height ) );
painter.drawPixmap( 4, knobPosY() - m_knob.height(), m_knob );
}

View File

@@ -1,9 +1,9 @@
/*
* lcd_spinbox.cpp - class lcdSpinBox, an improved QLCDNumber
*
* Copyright (c) 2005-2011 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2008 Paul Giblock <pgllama/at/gmail.com>
*
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* This program is free software; you can redistribute it and/or
@@ -23,8 +23,6 @@
*
*/
#include <QtGui/QApplication>
#include <QtGui/QLabel>
#include <QtGui/QMouseEvent>
@@ -42,228 +40,43 @@
lcdSpinBox::lcdSpinBox( int _num_digits, QWidget * _parent,
const QString & _name ) :
QWidget( _parent ),
IntModelView( new IntModel( 0, 0, 0, NULL, _name, true ), this ),
m_label(),
m_numDigits( _num_digits ),
lcdSpinBox::lcdSpinBox( int numDigits, QWidget* parent, const QString& name ) :
LcdWidget( numDigits, parent, name ),
IntModelView( new IntModel( 0, 0, 0, NULL, name, true ), this ),
m_origMousePos()
{
setEnabled( true );
setWindowTitle( _name );
m_lcdPixmap = new QPixmap( embed::getIconPixmap( "lcd_19green" ) );
m_cellWidth = m_lcdPixmap->size().width() / lcdSpinBox::charsPerPixmap;
m_cellHeight = m_lcdPixmap->size().height() / 2;
m_marginWidth = m_cellWidth / 2;
updateSize();
}
lcdSpinBox::lcdSpinBox( int _num_digits, const QString & _lcd_style,
QWidget * _parent, const QString & _name ) :
QWidget( _parent ),
IntModelView( new IntModel( 0, 0, 0, NULL, _name, true ), this ),
m_label(),
m_numDigits( _num_digits ),
lcdSpinBox::lcdSpinBox( int numDigits, const QString& style, QWidget* parent, const QString& name ) :
LcdWidget( numDigits, parent, name ),
IntModelView( new IntModel( 0, 0, 0, NULL, name, true ), this ),
m_origMousePos()
{
setEnabled( true );
setWindowTitle( _name );
// We should make a factory for these or something.
m_lcdPixmap = new QPixmap( embed::getIconPixmap( QString( "lcd_" +
_lcd_style ).toUtf8().constData() ) );
m_cellWidth = m_lcdPixmap->size().width() / lcdSpinBox::charsPerPixmap;
m_cellHeight = m_lcdPixmap->size().height() / 2;
m_marginWidth = m_cellWidth / 2;
updateSize();
}
lcdSpinBox::~lcdSpinBox()
{
delete m_lcdPixmap;
}
void lcdSpinBox::paintEvent( QPaintEvent * _me )
{
QRect ur = _me->rect();
QPainter p( this );
QSize cellSize( m_cellWidth, m_cellHeight );
QRect cellRect( 0, 0, m_cellWidth, m_cellHeight );
int margin = 1; // QStyle::PM_DefaultFrameWidth;
//int lcdWidth = m_cellWidth * m_numDigits + (margin*m_marginWidth)*2;
// p.translate( width() / 2 - lcdWidth / 2, 0 );
p.save();
p.translate( margin, margin );
// Left Margin
p.drawPixmap( cellRect, *m_lcdPixmap,
QRect( QPoint( charsPerPixmap*m_cellWidth,
isEnabled()?0:m_cellHeight ),
cellSize ) );
p.translate( m_marginWidth, 0 );
// Padding
for( int i=0; i < m_numDigits - m_display.length(); i++ )
{
p.drawPixmap( cellRect, *m_lcdPixmap,
QRect( QPoint( 10 * m_cellWidth, isEnabled()?0:m_cellHeight) , cellSize ) );
p.translate( m_cellWidth, 0 );
}
// Digits
for( int i=0; i < m_display.length(); i++ )
{
int val = m_display[i].digitValue();
if( val < 0 )
{
if( m_display[i] == '-' )
val = 11;
else
val = 10;
}
p.drawPixmap( cellRect, *m_lcdPixmap,
QRect( QPoint( val*m_cellWidth,
isEnabled()?0:m_cellHeight ),
cellSize ) );
p.translate( m_cellWidth, 0 );
}
// Right Margin
p.drawPixmap( QRect( 0, 0, m_marginWidth-1, m_cellHeight ), *m_lcdPixmap,
QRect( charsPerPixmap*m_cellWidth, isEnabled()?0:m_cellHeight,
m_cellWidth / 2, m_cellHeight ) );
p.restore();
// Border
QStyleOptionFrame opt;
opt.initFrom( this );
opt.state = QStyle::State_Sunken;
opt.rect = QRect( 0, 0, m_cellWidth * m_numDigits + (margin+m_marginWidth)*2 - 1,
m_cellHeight + (margin*2) );
style()->drawPrimitive( QStyle::PE_Frame, &opt, &p, this );
p.resetTransform();
// Label
if( !m_label.isEmpty() )
{
p.setFont( pointSize<6>( p.font() ) );
p.setPen( QColor( 64, 64, 64 ) );
p.drawText( width() / 2 -
p.fontMetrics().width( m_label ) / 2 + 1,
height(), m_label );
p.setPen( QColor( 255, 255, 255 ) );
p.drawText( width() / 2 -
p.fontMetrics().width( m_label ) / 2,
height() - 1, m_label );
}
}
void lcdSpinBox::update()
{
QString s = m_textForValue[model()->value()];
if( s == "" )
{
s = QString::number( model()->value() );
// TODO: if pad == true
/*
while( (int) s.length() < m_numDigits )
{
s = "0" + s;
}
*/
}
m_display = s;
setValue( model()->value() );
QWidget::update();
}
void lcdSpinBox::setLabel( const QString & _txt )
void lcdSpinBox::contextMenuEvent( QContextMenuEvent* event )
{
m_label = _txt;
updateSize();
}
void lcdSpinBox::setEnabled( bool _on )
{
QWidget::setEnabled( _on );
}
void lcdSpinBox::setMarginWidth( int _width )
{
m_marginWidth = _width;
updateSize();
}
void lcdSpinBox::updateSize()
{
int margin = 1;
if (m_label.isEmpty()) {
setFixedSize( m_cellWidth * m_numDigits + 2*(margin+m_marginWidth),
m_cellHeight + (2*margin) );
}
else {
setFixedSize( qMax<int>(
m_cellWidth * m_numDigits + 2*(margin+m_marginWidth),
QFontMetrics( pointSize<6>( font() ) ).width( m_label ) ),
m_cellHeight + (2*margin) + 10 );
}
update();
}
void lcdSpinBox::contextMenuEvent( QContextMenuEvent * _me )
{
m_origMousePos = _me->globalPos();
m_origMousePos = event->globalPos();
// for the case, the user clicked right while pressing left mouse-
// button, the context-menu appears while mouse-cursor is still hidden
@@ -279,30 +92,30 @@ void lcdSpinBox::contextMenuEvent( QContextMenuEvent * _me )
void lcdSpinBox::mousePressEvent( QMouseEvent * _me )
void lcdSpinBox::mousePressEvent( QMouseEvent* event )
{
if( _me->button() == Qt::LeftButton &&
! ( _me->modifiers() & Qt::ControlModifier ) &&
_me->y() < m_cellHeight + 2 )
if( event->button() == Qt::LeftButton &&
! ( event->modifiers() & Qt::ControlModifier ) &&
event->y() < cellHeight() + 2 )
{
m_origMousePos = _me->globalPos();
m_origMousePos = event->globalPos();
QApplication::setOverrideCursor( Qt::BlankCursor );
model()->prepareJournalEntryFromOldVal();
}
else
{
IntModelView::mousePressEvent( _me );
IntModelView::mousePressEvent( event );
}
}
void lcdSpinBox::mouseMoveEvent( QMouseEvent * _me )
void lcdSpinBox::mouseMoveEvent( QMouseEvent* event )
{
if( _me->buttons() & Qt::LeftButton )
if( event->buttons() & Qt::LeftButton )
{
int dy = _me->globalY() - m_origMousePos.y();
int dy = event->globalY() - m_origMousePos.y();
if( dy > 1 || dy < -1 )
{
model()->setInitValue( model()->value() -
@@ -316,7 +129,7 @@ void lcdSpinBox::mouseMoveEvent( QMouseEvent * _me )
void lcdSpinBox::mouseReleaseEvent( QMouseEvent * _me )
void lcdSpinBox::mouseReleaseEvent( QMouseEvent* event )
{
model()->addJournalEntryFromOldToCurVal();

View File

@@ -2,7 +2,7 @@
* pixmap_button.cpp - implementation of pixmap-button (often used as "themed"
* checkboxes/radiobuttons etc)
*
* Copyright (c) 2004-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -57,7 +57,7 @@ void pixmapButton::paintEvent( QPaintEvent * )
{
QPainter p( this );
if( model()->value() || m_pressed )
if( ( model() != NULL && model()->value() ) || m_pressed )
{
if( !m_activePixmap.isNull() )
{

View File

@@ -131,7 +131,7 @@ AutomationTrackView::AutomationTrackView( AutomationTrack * _at,
trackContainerView * _tcv ) :
trackView( _at, _tcv )
{
setFixedHeight( 32 );
setFixedHeight( 32 );
trackLabelButton * tlb = new trackLabelButton( this,
getTrackSettingsWidget() );
tlb->setIcon( embed::getIconPixmap( "automation_track" ) );

View File

@@ -2,7 +2,7 @@
* InstrumentTrack.cpp - implementation of instrument-track-class
* (window + data-structures)
*
* Copyright (c) 2004-2012 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -98,6 +98,7 @@ InstrumentTrack::InstrumentTrack( trackContainer * _tc ) :
m_midiPort( tr( "unnamed_track" ), engine::getMixer()->midiClient(),
this, this ),
m_notes(),
m_sustainPedalPressed( false ),
m_baseNoteModel( 0, 0, KeysPerOctave * NumOctaves - 1, this,
tr( "Base note" ) ),
m_volumeModel( DefaultVolume, MinVolume, MaxVolume, 0.1f, this,
@@ -220,6 +221,19 @@ void InstrumentTrack::processInEvent( const midiEvent & _me,
const midiTime & _time )
{
engine::getMixer()->lock();
// in the special case this event comes from a MIDI port, the instrument
// is MIDI based (VST plugin, Sf2Player etc.) and the user did not set
// a dedicated MIDI output channel, directly pass the MIDI event to the
// instrument plugin
if( _me.isFromMidiPort() && m_instrument->isMidiBased()/* &&
midiPort()->realOutputChannel() < 0 */ )
{
m_instrument->handleMidiEvent( _me, _time );
engine::getMixer()->unlock();
return;
}
switch( _me.m_type )
{
// we don't send MidiNoteOn, MidiNoteOff and MidiKeyPressure
@@ -303,6 +317,29 @@ void InstrumentTrack::processInEvent( const midiEvent & _me,
break;
case MidiControlChange:
if( _me.controllerNumber() == MidiControllerSustain )
{
if( _me.controllerValue() > MidiMaxControllerValue/2 )
{
m_sustainPedalPressed = true;
}
else
{
m_sustainPedalPressed = false;
}
}
if( _me.controllerNumber() == MidiControllerAllSoundOff ||
_me.controllerNumber() == MidiControllerAllNotesOff ||
_me.controllerNumber() == MidiControllerOmniOn ||
_me.controllerNumber() == MidiControllerOmniOff ||
_me.controllerNumber() == MidiControllerMonoOn ||
_me.controllerNumber() == MidiControllerPolyOn )
{
silenceAllNotes();
}
m_instrument->handleMidiEvent( _me, _time );
break;
case MidiProgramChange:
m_instrument->handleMidiEvent( _me, _time );
break;
@@ -1023,9 +1060,9 @@ void InstrumentTrackView::freeInstrumentTrackWindow()
model()->setHook( NULL );
m_window->setInstrumentTrackView( NULL );
m_window->parentWidget()->hide();
m_window->setModel(
engine::dummyTrackContainer()->
dummyInstrumentTrack() );
//m_window->setModel(
// engine::dummyTrackContainer()->
// dummyInstrumentTrack() );
m_window->updateInstrumentView();
s_windowCache << m_window;
}
@@ -1193,6 +1230,9 @@ class fxLineLcdSpinBox : public lcdSpinBox
virtual void mouseDoubleClickEvent ( QMouseEvent * _me )
{
engine::fxMixerView()->setCurrentFxLine( model()->value() );
engine::fxMixerView()->show();// show fxMixer window
engine::fxMixerView()->setFocus();// set focus to fxMixer window
//engine::getFxMixerView()->raise();
}
};

View File

@@ -1,7 +1,7 @@
/*
* bb_track.cpp - implementation of class bbTrack and bbTCO
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -33,6 +33,7 @@
#include "embed.h"
#include "engine.h"
#include "gui_templates.h"
#include "MainWindow.h"
#include "mixer.h"
#include "rename_dialog.h"
#include "song.h"
@@ -223,10 +224,9 @@ void bbTCOView::paintEvent( QPaintEvent * )
void bbTCOView::openInBBEditor()
{
engine::getBBTrackContainer()->setCurrentBB( bbTrack::numOfBBTrack(
m_bbTCO->getTrack() ) );
engine::getBBEditor()->show();
engine::getBBEditor()->setFocus();
engine::getBBTrackContainer()->setCurrentBB( bbTrack::numOfBBTrack( m_bbTCO->getTrack() ) );
engine::mainWindow()->toggleBBEditorWin( true );
}