Merge branch 'stable-1.2' into master (@liushuyu)

This commit is contained in:
Hyunin Song
2017-07-15 07:56:28 +09:00
113 changed files with 1513 additions and 609 deletions

View File

@@ -75,6 +75,10 @@ IF(NOT ("${OGGVORBIS_INCLUDE_DIR}" STREQUAL ""))
INCLUDE_DIRECTORIES("${OGGVORBIS_INCLUDE_DIR}")
ENDIF()
IF(NOT ("${LAME_INCLUDE_DIRS}" STREQUAL ""))
INCLUDE_DIRECTORIES("${LAME_INCLUDE_DIRS}")
ENDIF()
# Use libraries in non-standard directories (e.g., another version of Qt)
IF(LMMS_BUILD_LINUX)
LINK_LIBRARIES(-Wl,--enable-new-dtags)
@@ -136,6 +140,7 @@ SET(LMMS_REQUIRED_LIBS
${PULSEAUDIO_LIBRARIES}
${JACK_LIBRARIES}
${OGGVORBIS_LIBRARIES}
${LAME_LIBRARIES}
${SAMPLERATE_LIBRARIES}
${SNDFILE_LIBRARIES}
${EXTRA_LIBRARIES}
@@ -191,6 +196,7 @@ IF(LMMS_BUILD_WIN32)
"${MINGW_PREFIX}/bin/libvorbisfile-3.dll"
"${MINGW_PREFIX}/bin/libjpeg-9.dll"
"${MINGW_PREFIX}/bin/libogg-0.dll"
"${MINGW_PREFIX}/bin/libmp3lame-0.dll"
"${MINGW_PREFIX}/bin/libfftw3f-3.dll"
"${MINGW_PREFIX}/bin/libFLAC-8.dll"
"${MINGW_PREFIX}/bin/libpng16-16.dll"

View File

@@ -716,19 +716,19 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time )
float FloatModel::getRoundedValue() const
{
return static_cast<float>( static_cast<int>( value() / step<float>() + 0.5 ) ) * step<float>();
return qRound( value() / step<float>() ) * step<float>();
}
float FloatModel::getDigitCount()
int FloatModel::getDigitCount() const
{
float steptemp = step<float>();
int digits = 0;
while ( steptemp < 1 )
{
steptemp = steptemp / 0.1f;
steptemp = steptemp * 10.0f;
digits++;
}
return digits;

View File

@@ -69,6 +69,7 @@ set(LMMS_SRCS
core/audio/AudioAlsa.cpp
core/audio/AudioDevice.cpp
core/audio/AudioFileDevice.cpp
core/audio/AudioFileMP3.cpp
core/audio/AudioFileOgg.cpp
core/audio/AudioFileWave.cpp
core/audio/AudioJack.cpp

View File

@@ -63,7 +63,12 @@ ConfigManager::ConfigManager() :
// If we're in development (lmms is not installed) let's get the source and
// binary directories by reading the CMake Cache
QFile cmakeCache(qApp->applicationDirPath() + "/CMakeCache.txt");
QDir appPath = qApp->applicationDirPath();
// If in tests, get parent directory
if (appPath.dirName() == "tests") {
appPath.cdUp();
}
QFile cmakeCache(appPath.absoluteFilePath("CMakeCache.txt"));
if (cmakeCache.exists()) {
cmakeCache.open(QFile::ReadOnly);
QTextStream stream(&cmakeCache);
@@ -277,7 +282,8 @@ void ConfigManager::addRecentlyOpenedProject( const QString & file )
{
QFileInfo recentFile( file );
if( recentFile.suffix().toLower() == "mmp" ||
recentFile.suffix().toLower() == "mmpz" )
recentFile.suffix().toLower() == "mmpz" ||
recentFile.suffix().toLower() == "mpt" )
{
m_recentlyOpenedProjects.removeAll( file );
if( m_recentlyOpenedProjects.size() > 50 )
@@ -313,6 +319,16 @@ const QString & ConfigManager::value( const QString & cls,
const QString & ConfigManager::value( const QString & cls,
const QString & attribute,
const QString & defaultVal ) const
{
const QString & val = value( cls, attribute );
return val.isEmpty() ? defaultVal : val;
}
void ConfigManager::setValue( const QString & cls,
const QString & attribute,

View File

@@ -113,6 +113,7 @@ void LfoController::updateValueBuffer()
}
m_currentPhase = absFraction( phase - m_phaseOffset );
m_bufferLastUpdated = s_periods;
}
void LfoController::updatePhase()

View File

@@ -30,6 +30,7 @@
#include "AudioFileWave.h"
#include "AudioFileOgg.h"
#include "AudioFileMP3.h"
#ifdef LMMS_HAVE_SCHED_H
#include "sched.h"
@@ -48,6 +49,15 @@ const ProjectRenderer::FileEncodeDevice ProjectRenderer::fileEncodeDevices[] =
&AudioFileOgg::getInst
#else
NULL
#endif
},
{ ProjectRenderer::MP3File,
QT_TRANSLATE_NOOP( "ProjectRenderer", "Compressed MP3-File (*.mp3)" ),
".mp3",
#ifdef LMMS_HAVE_MP3LAME
&AudioFileMP3::getInst
#else
NULL
#endif
},
// ... insert your own file-encoder-infos here... may be one day the
@@ -93,6 +103,8 @@ ProjectRenderer::ProjectRenderer( const Mixer::qualitySettings & qualitySettings
ProjectRenderer::~ProjectRenderer()
{
Engine::mixer()->restoreAudioDevice(); // also deletes audio-dev
Engine::mixer()->changeQuality( m_oldQualitySettings );
}
@@ -172,10 +184,11 @@ void ProjectRenderer::run()
m_progress = 0;
std::pair<MidiTime, MidiTime> exportEndpoints = Engine::getSong()->getExportEndpoints();
tick_t startTick = exportEndpoints.first.getTicks();
tick_t lengthTicks = exportEndpoints.second.getTicks() - startTick;
tick_t endTick = exportEndpoints.second.getTicks();
tick_t lengthTicks = endTick - startTick;
// Continually track and emit progress percentage to listeners
while( Engine::getSong()->isExportDone() == false &&
while( exportPos.getTicks() < endTick &&
Engine::getSong()->isExporting() == true
&& !m_abort )
{
@@ -190,12 +203,8 @@ void ProjectRenderer::run()
Engine::getSong()->stopExport();
const QString f = m_fileDev->outputFile();
Engine::mixer()->restoreAudioDevice(); // also deletes audio-dev
Engine::mixer()->changeQuality( m_oldQualitySettings );
// if the user aborted export-process, the file has to be deleted
const QString f = m_fileDev->outputFile();
if( m_abort )
{
QFile( f ).remove();

View File

@@ -1411,25 +1411,35 @@ void SampleBuffer::setReversed( bool _on )
QString SampleBuffer::tryToMakeRelative( const QString & _file )
QString SampleBuffer::tryToMakeRelative( const QString & file )
{
if( QFileInfo( _file ).isRelative() == false )
if( QFileInfo( file ).isRelative() == false )
{
QString f = QString( _file ).replace( QDir::separator(), '/' );
QString fsd = ConfigManager::inst()->factorySamplesDir();
QString usd = ConfigManager::inst()->userSamplesDir();
fsd.replace( QDir::separator(), '/' );
usd.replace( QDir::separator(), '/' );
if( f.startsWith( fsd ) )
QString f = QString( file ).replace( QDir::separator(), '/' );
// First, look in factory samples
// Isolate "samples/" from "data:/samples/"
QString samplesSuffix = ConfigManager::inst()->factorySamplesDir().mid( ConfigManager::inst()->dataDir().length() );
// Iterate over all valid "data:/" searchPaths
for ( const QString & path : QDir::searchPaths( "data" ) )
{
return QString( f ).mid( fsd.length() );
QString samplesPath = QString( path + samplesSuffix ).replace( QDir::separator(), '/' );
if ( f.startsWith( samplesPath ) )
{
return QString( f ).mid( samplesPath.length() );
}
}
else if( f.startsWith( usd ) )
// Next, look in user samples
QString usd = ConfigManager::inst()->userSamplesDir();
usd.replace( QDir::separator(), '/' );
if( f.startsWith( usd ) )
{
return QString( f ).mid( usd.length() );
}
}
return _file;
return file;
}

View File

@@ -464,29 +464,6 @@ void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fp
}
}
bool Song::isExportDone() const
{
if ( m_renderBetweenMarkers )
{
return m_exporting == true &&
m_playPos[Mode_PlaySong].getTicks() >=
m_playPos[Mode_PlaySong].m_timeLine->loopEnd().getTicks();
}
if( m_exportLoop )
{
return m_exporting == true &&
m_playPos[Mode_PlaySong].getTicks() >=
length() * ticksPerTact();
}
else
{
return m_exporting == true &&
m_playPos[Mode_PlaySong].getTicks() >=
( length() + 1 ) * ticksPerTact();
}
}
std::pair<MidiTime, MidiTime> Song::getExportEndpoints() const
{
if ( m_renderBetweenMarkers )
@@ -1077,6 +1054,27 @@ void Song::loadProject( const QString & fileName )
}
node = dataFile.content().firstChild();
QDomNodeList tclist=dataFile.content().elementsByTagName("trackcontainer");
m_nLoadingTrack=0;
for( int i=0,n=tclist.count(); i<n; ++i )
{
QDomNode nd=tclist.at(i).firstChild();
while(!nd.isNull())
{
if( nd.isElement() && nd.nodeName() == "track" )
{
++m_nLoadingTrack;
if( nd.toElement().attribute("type").toInt() == Track::BBTrack )
{
n += nd.toElement().elementsByTagName("bbtrack").at(0)
.toElement().firstChildElement().childNodes().count();
}
nd=nd.nextSibling();
}
}
}
while( !node.isNull() )
{
if( node.isElement() )
@@ -1339,7 +1337,8 @@ void Song::exportProject( bool multiExport )
efd.setFileMode( FileDialog::AnyFile );
int idx = 0;
QStringList types;
while( ProjectRenderer::fileEncodeDevices[idx].m_fileFormat != ProjectRenderer::NumFileFormats )
while( ProjectRenderer::fileEncodeDevices[idx].m_fileFormat != ProjectRenderer::NumFileFormats &&
ProjectRenderer::fileEncodeDevices[idx].isAvailable())
{
types << tr( ProjectRenderer::fileEncodeDevices[idx].m_description );
++idx;
@@ -1360,13 +1359,14 @@ void Song::exportProject( bool multiExport )
efd.setWindowTitle( tr( "Select file for project-export..." ) );
}
QString suffix = "wav";
efd.setDefaultSuffix( suffix );
efd.setAcceptMode( FileDialog::AcceptSave );
if( efd.exec() == QDialog::Accepted && !efd.selectedFiles().isEmpty() &&
!efd.selectedFiles()[0].isEmpty() )
{
QString suffix = "";
QString exportFileName = efd.selectedFiles()[0];
if ( !multiExport )
{
@@ -1378,19 +1378,18 @@ void Song::exportProject( bool multiExport )
// Get first extension from selected dropdown.
// i.e. ".wav" from "WAV-File (*.wav), Dummy-File (*.dum)"
suffix = efd.selectedNameFilter().mid( stx + 2, etx - stx - 2 ).split( " " )[0].trimmed();
exportFileName.remove( "." + suffix, Qt::CaseInsensitive );
if ( efd.selectedFiles()[0].endsWith( suffix ) )
{
suffix = "";
if( VersionedSaveDialog::fileExistsQuery( exportFileName + suffix,
tr( "Save project" ) ) )
{
exportFileName += suffix;
}
}
}
}
if( VersionedSaveDialog::fileExistsQuery( exportFileName + suffix,
tr( "Save project" ) ) )
{
exportFileName += suffix;
}
ExportProjectDialog epd( exportFileName, gui->mainWindow(), multiExport );
epd.exec();
}

View File

@@ -86,25 +86,18 @@ void TrackContainer::loadSettings( const QDomElement & _this )
static QProgressDialog * pd = NULL;
bool was_null = ( pd == NULL );
int start_val = 0;
if( !journalRestore && gui != nullptr )
{
if( pd == NULL )
{
pd = new QProgressDialog( tr( "Loading project..." ),
tr( "Cancel" ), 0,
_this.childNodes().count(),
Engine::getSong()->getLoadingTrackCount(),
gui->mainWindow() );
pd->setWindowModality( Qt::ApplicationModal );
pd->setWindowTitle( tr( "Please wait..." ) );
pd->show();
}
else
{
start_val = pd->value();
pd->setMaximum( pd->maximum() +
_this.childNodes().count() );
}
}
QDomNode node = _this.firstChild();
@@ -124,6 +117,14 @@ void TrackContainer::loadSettings( const QDomElement & _this )
if( node.isElement() &&
!node.toElement().attribute( "metadata" ).toInt() )
{
QString trackName = node.toElement().hasAttribute( "name" ) ?
node.toElement().attribute( "name" ) :
node.firstChild().toElement().attribute( "name" );
if( pd != NULL )
{
pd->setLabelText( tr("Loading Track %1 (%2/Total %3)").arg( trackName ).
arg( pd->value() + 1 ).arg( Engine::getSong()->getLoadingTrackCount() ) );
}
Track::create( node.toElement(), this );
}
node = node.nextSibling();
@@ -131,7 +132,6 @@ void TrackContainer::loadSettings( const QDomElement & _this )
if( pd != NULL )
{
pd->setValue( start_val + _this.childNodes().count() );
if( was_null )
{
delete pd;

View File

@@ -0,0 +1,133 @@
/*
* AudioFileMP3.cpp - Audio-device which encodes a wave stream into
* an MP3 file. This is used for song export.
*
* Copyright (c) 2017 to present Michael Gregorius <michael.gregorius.git/at/arcor[dot]de>
*
* This file is part of LMMS - https://lmms.io
*
* 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 "AudioFileMP3.h"
#ifdef LMMS_HAVE_MP3LAME
#include "Mixer.h"
#include <cassert>
AudioFileMP3::AudioFileMP3( OutputSettings const & outputSettings,
const ch_cnt_t channels,
bool & successful,
const QString & file,
Mixer* mixer ) :
AudioFileDevice( outputSettings, channels, file, mixer )
{
successful = true;
// For now only accept stereo sources
successful &= channels == 2;
successful &= initEncoder();
successful &= outputFileOpened();
}
AudioFileMP3::~AudioFileMP3()
{
flushRemainingBuffers();
tearDownEncoder();
}
void AudioFileMP3::writeBuffer( const surroundSampleFrame * _buf,
const fpp_t _frames,
const float _master_gain )
{
if (_frames < 1)
{
return;
}
// TODO Why isn't the gain applied by the driver but inside the device?
std::vector<float> interleavedDataBuffer(_frames * 2);
for (fpp_t i = 0; i < _frames; ++i)
{
interleavedDataBuffer[2*i] = _buf[i][0] * _master_gain;
interleavedDataBuffer[2*i + 1] = _buf[i][1] * _master_gain;
}
size_t minimumBufferSize = 1.25 * _frames + 7200;
std::vector<unsigned char> encodingBuffer(minimumBufferSize);
int bytesWritten = lame_encode_buffer_interleaved_ieee_float(m_lame, &interleavedDataBuffer[0], _frames, &encodingBuffer[0], static_cast<int>(encodingBuffer.size()));
assert (bytesWritten >= 0);
writeData(&encodingBuffer[0], bytesWritten);
}
void AudioFileMP3::flushRemainingBuffers()
{
// The documentation states that flush should have at least 7200 bytes. So let's be generous.
std::vector<unsigned char> encodingBuffer(7200 * 4);
int bytesWritten = lame_encode_flush(m_lame, &encodingBuffer[0], static_cast<int>(encodingBuffer.size()));
assert (bytesWritten >= 0);
writeData(&encodingBuffer[0], bytesWritten);
}
MPEG_mode mapToMPEG_mode(OutputSettings::StereoMode stereoMode)
{
switch (stereoMode)
{
case OutputSettings::StereoMode_Stereo:
return STEREO;
case OutputSettings::StereoMode_JointStereo:
return JOINT_STEREO;
case OutputSettings::StereoMode_Mono:
return MONO;
default:
return NOT_SET;
}
}
bool AudioFileMP3::initEncoder()
{
m_lame = lame_init();
// Handle stereo/joint/mono settings
OutputSettings::StereoMode stereoMode = getOutputSettings().getStereoMode();
lame_set_mode(m_lame, mapToMPEG_mode(stereoMode));
// Handle bit rate settings
OutputSettings::BitRateSettings bitRateSettings = getOutputSettings().getBitRateSettings();
int bitRate = static_cast<int>(bitRateSettings.getBitRate());
lame_set_VBR(m_lame, vbr_off);
lame_set_brate(m_lame, bitRate);
// Add a comment
id3tag_set_comment(m_lame, "Created with LMMS");
return lame_init_params(m_lame) != -1;
}
void AudioFileMP3::tearDownEncoder()
{
lame_close(m_lame);
}
#endif

View File

@@ -70,8 +70,7 @@ inline int AudioFileOgg::writePage()
bool AudioFileOgg::startEncoding()
{
vorbis_comment vc;
const char * comments = "Cool=This song has been made using Linux "
"MultiMedia Studio";
const char * comments = "Cool=This song has been made using LMMS";
int comment_length = strlen( comments );
char * user_comments = new char[comment_length + 1];
strcpy( user_comments, comments );
@@ -100,7 +99,7 @@ bool AudioFileOgg::startEncoding()
m_rate = 48000;
setSampleRate( 48000 );
}
m_serialNo = 0; // track-num?
m_comments = &vc; // comments for ogg-file
// Have vorbisenc choose a mode for us
@@ -135,6 +134,10 @@ bool AudioFileOgg::startEncoding()
vorbis_analysis_init( &m_vd, &m_vi );
vorbis_block_init( &m_vd, &m_vb );
// We give our ogg file a random serial number and avoid
// 0 and UINT32_MAX which can get you into trouble.
qsrand( time( 0 ) );
m_serialNo = 0xD0000000 + qrand() % 0x0FFFFFFF;
ogg_stream_init( &m_os, m_serialNo );
// Now, build the three header packets and send through to the stream

View File

@@ -79,7 +79,12 @@ bool AudioFileWave::startEncoding()
outputFile().toUtf8().constData(),
#endif
SFM_WRITE, &m_si );
// Prevent fold overs when encountering clipped data
sf_command(m_sf, SFC_SET_CLIPPING, NULL, SF_TRUE);
sf_set_string ( m_sf, SF_STR_SOFTWARE, "LMMS" );
return true;
}

View File

@@ -160,7 +160,7 @@ int calc13octaveband31(float *absspec_buffer, float *subbands, int num_spec, flo
{
static const int onethirdoctavecenterfr[] = {20, 25, 31, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000, 10000, 12500, 16000, 20000};
int i, j;
float f_min, f_max, frequency, bandwith;
float f_min, f_max, frequency, bandwidth;
int j_min, j_max=0;
float fpower;
@@ -189,13 +189,13 @@ static const int onethirdoctavecenterfr[] = {20, 25, 31, 40, 50, 63, 80, 100, 12
{
subbands[i]=0;
// calculate bandwith for subband
// calculate bandwidth for subband
frequency=onethirdoctavecenterfr[i];
bandwith=(pow(2, 1.0/3.0)-1)*frequency;
bandwidth=(pow(2, 1.0/3.0)-1)*frequency;
f_min=frequency-bandwith/2.0;
f_max=frequency+bandwith/2.0;
f_min=frequency-bandwidth/2.0;
f_max=frequency+bandwidth/2.0;
j_min=(int)(f_min/max_frequency*(float)num_spec);

View File

@@ -151,6 +151,7 @@ void printHelp()
" [ -i <method> ]\n"
" [ --import <in> [-e]]\n"
" [ -l ]\n"
" [ -m <mode>]\n"
" [ -o <path> ]\n"
" [ -p <out> ]\n"
" [ -r <project file> ] [ options ]\n"
@@ -165,7 +166,7 @@ void printHelp()
"-c, --config <configfile> Get the configuration from <configfile>\n"
"-d, --dump <in> Dump XML of compressed file <in>\n"
"-f, --format <format> Specify format of render-output where\n"
" Format is either 'wav' or 'ogg'.\n"
" Format is either 'wav', 'ogg' or 'mp3'.\n"
" --geometry <geometry> Specify the size and position of the main window\n"
" geometry is <xsizexysize+xoffset+yoffsety>.\n"
"-h, --help Show this usage information and exit.\n"
@@ -178,6 +179,12 @@ void printHelp()
" --import <in> [-e] Import MIDI file <in>.\n"
" If -e is specified lmms exits after importing the file.\n"
"-l, --loop Render as a loop\n"
"-m, --mode Stereo mode used for MP3 export\n"
" Possible values: s, j, m\n"
" s: Stereo\n"
" j: Joint Stereo\n"
" m: Mono\n"
" Default: j\n"
"-o, --output <path> Render into <path>\n"
" For --render, provide a file path\n"
" For --rendertracks, provide a directory path\n"
@@ -291,7 +298,7 @@ int main( int argc, char * * argv )
{
printf( "LMMS cannot be run as root.\nUse \"--allowroot\" to override.\n\n" );
return EXIT_FAILURE;
}
}
#endif
QCoreApplication * app = coreOnly ?
@@ -299,7 +306,7 @@ int main( int argc, char * * argv )
new MainApplication( argc, argv );
Mixer::qualitySettings qs( Mixer::qualitySettings::Mode_HighQuality );
OutputSettings os( 44100, OutputSettings::BitRateSettings(160, false), OutputSettings::Depth_16Bit );
OutputSettings os( 44100, OutputSettings::BitRateSettings(160, false), OutputSettings::Depth_16Bit, OutputSettings::StereoMode_JointStereo );
ProjectRenderer::ExportFileFormats eff = ProjectRenderer::WaveFile;
// second of two command-line parsing stages
@@ -353,7 +360,7 @@ int main( int argc, char * * argv )
printf( "\nOption \"--allowroot\" will be ignored on this platform.\n\n" );
}
#endif
}
else if( arg == "--dump" || arg == "-d" )
{
@@ -430,6 +437,12 @@ int main( int argc, char * * argv )
{
eff = ProjectRenderer::OggFile;
}
#endif
#ifdef LMMS_HAVE_MP3LAME
else if( ext == "mp3" )
{
eff = ProjectRenderer::MP3File;
}
#endif
else
{
@@ -485,6 +498,38 @@ int main( int argc, char * * argv )
else
{
printf( "\nInvalid bitrate %s.\n\n"
"Try \"%s --help\" for more information.\n\n", argv[i], argv[0] );
return EXIT_FAILURE;
}
}
else if( arg == "--mode" || arg == "-m" )
{
++i;
if( i == argc )
{
printf( "\nNo stereo mode specified.\n\n"
"Try \"%s --help\" for more information.\n\n", argv[0] );
return EXIT_FAILURE;
}
QString const mode( argv[i] );
if( mode == "s" )
{
os.setStereoMode(OutputSettings::StereoMode_Stereo);
}
else if( mode == "j" )
{
os.setStereoMode(OutputSettings::StereoMode_JointStereo);
}
else if( mode == "m" )
{
os.setStereoMode(OutputSettings::StereoMode_Mono);
}
else
{
printf( "\nInvalid stereo mode %s.\n\n"
"Try \"%s --help\" for more information.\n\n", argv[i], argv[0] );
return EXIT_FAILURE;
}
@@ -778,10 +823,6 @@ int main( int argc, char * * argv )
" <td><b>%4</b></td>"
" <td>%5</td>"
" </tr>"
" <tr>"
" <td><b>%6</b></td>"
" <td>%7</td>"
" </tr>"
"</table>"
"</html>" ).arg(
MainWindow::tr( "There is a recovery file present. "
@@ -792,10 +833,6 @@ int main( int argc, char * * argv )
MainWindow::tr( "Recover" ),
MainWindow::tr( "Recover the file. Please don't run "
"multiple instances of LMMS when you do this." ),
MainWindow::tr( "Ignore" ),
MainWindow::tr( "Launch LMMS as usual but with "
"automatic backup disabled to prevent the "
"present recover file from being overwritten." ),
MainWindow::tr( "Discard" ),
MainWindow::tr( "Launch a default session and delete "
"the restored files. This is not reversible." )
@@ -807,38 +844,32 @@ int main( int argc, char * * argv )
QPushButton * recover;
QPushButton * discard;
QPushButton * ignore;
QPushButton * exit;
#if QT_VERSION >= 0x050000
// setting all buttons to the same roles allows us
// setting all buttons to the same roles allows us
// to have a custom layout
discard = mb.addButton( MainWindow::tr( "Discard" ),
QMessageBox::AcceptRole );
ignore = mb.addButton( MainWindow::tr( "Ignore" ),
QMessageBox::AcceptRole );
recover = mb.addButton( MainWindow::tr( "Recover" ),
QMessageBox::AcceptRole );
# else
# else
// in qt4 the button order is reversed
recover = mb.addButton( MainWindow::tr( "Recover" ),
QMessageBox::AcceptRole );
ignore = mb.addButton( MainWindow::tr( "Ignore" ),
QMessageBox::AcceptRole );
discard = mb.addButton( MainWindow::tr( "Discard" ),
QMessageBox::AcceptRole );
#endif
// have a hidden exit button
exit = mb.addButton( "", QMessageBox::RejectRole);
exit->setVisible(false);
// set icons
recover->setIcon( embed::getIconPixmap( "recover" ) );
discard->setIcon( embed::getIconPixmap( "discard" ) );
ignore->setIcon( embed::getIconPixmap( "ignore" ) );
mb.setDefaultButton( recover );
mb.setEscapeButton( exit );
@@ -853,13 +884,6 @@ int main( int argc, char * * argv )
fileToLoad = recoveryFile;
gui->mainWindow()->setSession( MainWindow::SessionState::Recover );
}
else if( mb.clickedButton() == ignore )
{
if( autoSaveEnabled )
{
gui->mainWindow()->setSession( MainWindow::SessionState::Limited );
}
}
else // Exit
{
return 0;
@@ -902,20 +926,19 @@ int main( int argc, char * * argv )
}
}
// If enabled, open last project if there is one. Else, create
// a new one. Also skip recently opened file if limited session to
// lower the chance of opening an already opened file.
// a new one.
else if( ConfigManager::inst()->
value( "app", "openlastproject" ).toInt() &&
!ConfigManager::inst()->
recentlyOpenedProjects().isEmpty() &&
gui->mainWindow()->getSession() !=
MainWindow::SessionState::Limited )
!recoveryFilePresent )
{
QString f = ConfigManager::inst()->
recentlyOpenedProjects().first();
QFileInfo recentFile( f );
if ( recentFile.exists() )
if ( recentFile.exists() &&
recentFile.suffix().toLower() != "mpt" )
{
Engine::getSong()->loadProject( f );
}
@@ -932,8 +955,7 @@ int main( int argc, char * * argv )
// Finally we start the auto save timer and also trigger the
// autosave one time as recover.mmp is a signal to possible other
// instances of LMMS.
if( autoSaveEnabled &&
gui->mainWindow()->getSession() != MainWindow::SessionState::Limited )
if( autoSaveEnabled )
{
gui->mainWindow()->autoSaveTimerReset();
gui->mainWindow()->autoSave();

View File

@@ -67,6 +67,11 @@ void MidiClient::addPort( MidiPort* port )
void MidiClient::removePort( MidiPort* port )
{
if( ! port )
{
return;
}
QVector<MidiPort *>::Iterator it =
qFind( m_midiPorts.begin(), m_midiPorts.end(), port );
if( it != m_midiPorts.end() )

View File

@@ -129,11 +129,11 @@ void MidiPort::processInEvent( const MidiEvent& event, const MidiTime& time )
{
return;
}
}
if( fixedInputVelocity() >= 0 && inEvent.velocity() > 0 )
{
inEvent.setVelocity( fixedInputVelocity() );
if( fixedInputVelocity() >= 0 && inEvent.velocity() > 0 )
{
inEvent.setVelocity( fixedInputVelocity() );
}
}
m_midiEventProcessor->processInEvent( inEvent, time );

View File

@@ -85,6 +85,7 @@ SET(LMMS_SRCS
gui/widgets/ToolButton.cpp
gui/widgets/ToolTip.cpp
gui/widgets/TrackLabelButton.cpp
gui/widgets/TrackRenameLineEdit.cpp
gui/widgets/VisualizationWidget.cpp
PARENT_SCOPE

View File

@@ -58,7 +58,7 @@ ExportProjectDialog::ExportProjectDialog( const QString & _file_name,
int cbIndex = 0;
for( int i = 0; i < ProjectRenderer::NumFileFormats; ++i )
{
if( ProjectRenderer::fileEncodeDevices[i].m_getDevInst != NULL )
if( ProjectRenderer::fileEncodeDevices[i].isAvailable() )
{
// get the extension of this format
QString renderExt = ProjectRenderer::fileEncodeDevices[i].m_extension;
@@ -128,7 +128,20 @@ void ExportProjectDialog::closeEvent( QCloseEvent * _ce )
}
OutputSettings::StereoMode mapToStereoMode(int index)
{
switch (index)
{
case 0:
return OutputSettings::StereoMode_Stereo;
case 1:
return OutputSettings::StereoMode_JointStereo;
case 2:
return OutputSettings::StereoMode_Mono;
default:
return OutputSettings::StereoMode_Stereo;
}
}
void ExportProjectDialog::startExport()
{
@@ -146,7 +159,8 @@ void ExportProjectDialog::startExport()
OutputSettings os = OutputSettings(
samplerates[ samplerateCB->currentIndex() ],
bitRateSettings,
static_cast<OutputSettings::BitDepth>( depthCB->currentIndex() ) );
static_cast<OutputSettings::BitDepth>( depthCB->currentIndex() ),
mapToStereoMode(stereoModeComboBox->currentIndex()) );
m_renderManager = new RenderManager( qs, os, m_ft, m_fileName );
@@ -181,6 +195,8 @@ ProjectRenderer::ExportFileFormats convertIndexToExportFileFormat(int index)
return ProjectRenderer::WaveFile;
case 1:
return ProjectRenderer::OggFile;
case 2:
return ProjectRenderer::MP3File;
default:
Q_ASSERT(false);
break;
@@ -195,10 +211,23 @@ void ExportProjectDialog::onFileFormatChanged(int index)
ProjectRenderer::ExportFileFormats exportFormat =
convertIndexToExportFileFormat(index);
bool bitRateControlsEnabled = exportFormat == ProjectRenderer::OggFile;
bool stereoModeVisible = exportFormat == ProjectRenderer::MP3File;
bool sampleRateControlsVisible = exportFormat != ProjectRenderer::MP3File;
bool bitRateControlsEnabled =
(exportFormat == ProjectRenderer::OggFile ||
exportFormat == ProjectRenderer::MP3File);
bool bitDepthControlEnabled = exportFormat == ProjectRenderer::WaveFile;
bool variableBitrateVisible = exportFormat != ProjectRenderer::MP3File;
stereoModeWidget->setVisible(stereoModeVisible);
sampleRateWidget->setVisible(sampleRateControlsVisible);
bitrateWidget->setVisible(bitRateControlsEnabled);
checkBoxVariableBitRate->setVisible(variableBitrateVisible);
depthWidget->setVisible(bitDepthControlEnabled);
}

View File

@@ -664,10 +664,6 @@ void MainWindow::resetWindowTitle()
{
title += " - " + tr( "Recover session. Please save your work!" );
}
if( getSession() == Limited )
{
title += " - " + tr( "Automatic backup disabled. Remember to save your work!" );
}
setWindowTitle( title + " - " + tr( "LMMS %1" ).arg( LMMS_VERSION ) );
}
@@ -738,7 +734,7 @@ void MainWindow::clearKeyModifiers()
void MainWindow::saveWidgetState( QWidget * _w, QDomElement & _de, QSize const & sizeIfInvisible )
void MainWindow::saveWidgetState( QWidget * _w, QDomElement & _de )
{
// If our widget is the main content of a window (e.g. piano roll, FxMixer, etc),
// we really care about the position of the *window* - not the position of the widget within its window
@@ -761,7 +757,7 @@ void MainWindow::saveWidgetState( QWidget * _w, QDomElement & _de, QSize const &
_de.setAttribute( "x", normalGeom.x() );
_de.setAttribute( "y", normalGeom.y() );
QSize sizeToStore = visible ? normalGeom.size() : sizeIfInvisible;
QSize sizeToStore = normalGeom.size();
_de.setAttribute( "width", sizeToStore.width() );
_de.setAttribute( "height", sizeToStore.height() );
}
@@ -773,8 +769,8 @@ void MainWindow::restoreWidgetState( QWidget * _w, const QDomElement & _de )
{
QRect r( qMax( 1, _de.attribute( "x" ).toInt() ),
qMax( 1, _de.attribute( "y" ).toInt() ),
qMax( 100, _de.attribute( "width" ).toInt() ),
qMax( 100, _de.attribute( "height" ).toInt() ) );
qMax( _w->sizeHint().width(), _de.attribute( "width" ).toInt() ),
qMax( _w->minimumHeight(), _de.attribute( "height" ).toInt() ) );
if( _de.hasAttribute( "visible" ) && !r.isNull() )
{
// If our widget is the main content of a window (e.g. piano roll, FxMixer, etc),
@@ -880,8 +876,8 @@ void MainWindow::updateRecentlyOpenedProjectsMenu()
m_recentlyOpenedProjectsMenu->clear();
QStringList rup = ConfigManager::inst()->recentlyOpenedProjects();
// The file history goes 30 deep but we only show the 15
// most recent ones that we can open.
// The file history goes 50 deep but we only show the 15
// most recent ones that we can open and omit .mpt files.
int shownInMenu = 0;
for( QStringList::iterator it = rup.begin(); it != rup.end(); ++it )
{
@@ -889,6 +885,11 @@ void MainWindow::updateRecentlyOpenedProjectsMenu()
if ( recentFile.exists() &&
*it != ConfigManager::inst()->recoveryFile() )
{
if( recentFile.suffix().toLower() == "mpt" )
{
continue;
}
m_recentlyOpenedProjectsMenu->addAction(
embed::getIconPixmap( "project_file" ), *it );
#ifdef LMMS_BUILD_APPLE
@@ -1374,8 +1375,8 @@ void MainWindow::closeEvent( QCloseEvent * _ce )
if( mayChangeProject(true) )
{
// delete recovery file
if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt()
&& getSession() != Limited )
if( ConfigManager::inst()->
value( "ui", "enableautosave" ).toInt() )
{
sessionCleanup();
_ce->accept();
@@ -1562,8 +1563,7 @@ void MainWindow::autoSave()
// from the timer where we need to do extra tests.
void MainWindow::runAutoSave()
{
if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() &&
getSession() != Limited )
if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() )
{
autoSave();
autoSaveTimerReset(); // Reset timer

View File

@@ -119,8 +119,8 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
#endif
m_backgroundArtwork( QDir::toNativeSeparators( ConfigManager::inst()->backgroundArtwork() ) ),
m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ),
m_enableAutoSave( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() ),
m_enableRunningAutoSave( ConfigManager::inst()->value( "ui", "enablerunningautosave" ).toInt() ),
m_enableAutoSave( ConfigManager::inst()->value( "ui", "enableautosave", "1" ).toInt() ),
m_enableRunningAutoSave( ConfigManager::inst()->value( "ui", "enablerunningautosave", "1" ).toInt() ),
m_saveInterval( ConfigManager::inst()->value( "ui", "saveinterval" ).toInt() < 1 ?
MainWindow::DEFAULT_SAVE_INTERVAL_MINUTES :
ConfigManager::inst()->value( "ui", "saveinterval" ).toInt() ),
@@ -131,7 +131,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
m_syncVSTPlugins( ConfigManager::inst()->value( "ui",
"syncvstplugins" ).toInt() ),
m_animateAFP(ConfigManager::inst()->value( "ui",
"animateafp").toInt() ),
"animateafp", "1" ).toInt() ),
m_printNoteLabels(ConfigManager::inst()->value( "ui",
"printnotelabels").toInt() ),
m_displayWaveform(ConfigManager::inst()->value( "ui",

View File

@@ -94,6 +94,8 @@ TimeLineWidget::TimeLineWidget( const int xoff, const int yoff, const float ppt,
connect( updateTimer, SIGNAL( timeout() ),
this, SLOT( updatePosition() ) );
updateTimer->start( 50 );
connect( Engine::getSong(), SIGNAL( timeSignatureChanged( int,int ) ),
this, SLOT( update() ) );
}

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>715</width>
<height>447</height>
<height>491</height>
</rect>
</property>
<property name="minimumSize">
@@ -45,39 +45,48 @@
<widget class="QComboBox" name="fileFormatCB"/>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Samplerate:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="samplerateCB">
<item>
<property name="text">
<string>44100 Hz</string>
<widget class="QWidget" name="sampleRateWidget" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
</item>
<item>
<property name="text">
<string>48000 Hz</string>
</property>
</item>
<item>
<property name="text">
<string>88200 Hz</string>
</property>
</item>
<item>
<property name="text">
<string>96000 Hz</string>
</property>
</item>
<item>
<property name="text">
<string>192000 Hz</string>
</property>
</item>
<item>
<widget class="QLabel" name="labelSampleRate">
<property name="text">
<string>Samplerate:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="samplerateCB">
<item>
<property name="text">
<string>44100 Hz</string>
</property>
</item>
<item>
<property name="text">
<string>48000 Hz</string>
</property>
</item>
<item>
<property name="text">
<string>88200 Hz</string>
</property>
</item>
<item>
<property name="text">
<string>96000 Hz</string>
</property>
</item>
<item>
<property name="text">
<string>192000 Hz</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@@ -124,6 +133,44 @@
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="stereoModeWidget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelStereoMode_3">
<property name="text">
<string>Stereo mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="stereoModeComboBox">
<property name="currentIndex">
<number>1</number>
</property>
<item>
<property name="text">
<string>Stereo</string>
</property>
</item>
<item>
<property name="text">
<string>Joint Stereo</string>
</property>
</item>
<item>
<property name="text">
<string>Mono</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="bitrateWidget" native="true">
<layout class="QVBoxLayout">

View File

@@ -69,7 +69,7 @@ QPixmap * AutomationEditor::s_toolYFlip = NULL;
QPixmap * AutomationEditor::s_toolXFlip = NULL;
const QVector<double> AutomationEditor::m_zoomXLevels =
{ 8.0f, 4.0f, 2.0f, 1.0f, 0.5f, 0.25f, 0.125f };
{ 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f };
@@ -239,7 +239,7 @@ void AutomationEditor::setCurrentPattern(AutomationPattern * new_pattern )
void AutomationEditor::saveSettings(QDomDocument & doc, QDomElement & dom_parent)
{
MainWindow::saveWidgetState(parentWidget(), dom_parent, QSize( 640, 400 ));
MainWindow::saveWidgetState( parentWidget(), dom_parent );
}
@@ -1233,18 +1233,20 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
}
}
// alternating shades for better contrast
// count the bars which disappear on left by scrolling
float timeSignature = static_cast<float>( Engine::getSong()->getTimeSigModel().getNumerator() )
/ static_cast<float>( Engine::getSong()->getTimeSigModel().getDenominator() );
float zoomFactor = m_zoomXLevels[m_zoomingXModel.value()];
int barCount = m_currentPosition / MidiTime::ticksPerTact();
int leftBars = m_currentPosition * zoomFactor / m_ppt;
//the bars which disappears at the left side by scrolling
int leftBars = m_currentPosition * zoomFactor / MidiTime::ticksPerTact();
for( int x = VALUES_WIDTH; x < width() + m_currentPosition * zoomFactor; x += m_ppt, ++barCount )
//iterates the visible bars and draw the shading on uneven bars
for( int x = VALUES_WIDTH, barCount = leftBars; x < width() + m_currentPosition * zoomFactor / timeSignature; x += m_ppt, ++barCount )
{
if( ( barCount + leftBars ) % 2 != 0 )
{
p.fillRect( x - m_currentPosition * zoomFactor, TOP_MARGIN, m_ppt,
p.fillRect( x - m_currentPosition * zoomFactor / timeSignature, TOP_MARGIN, m_ppt,
height() - ( SCROLLBAR_SIZE + TOP_MARGIN ), backgroundShade() );
}
}
@@ -1301,7 +1303,7 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
//Don't bother doing/rendering anything if there is no automation points
if( time_map.size() > 0 )
{
timeMap::iterator it = time_map.begin();
timeMap::iterator it = time_map.begin();
while( it+1 != time_map.end() )
{
// skip this section if it occurs completely before the
@@ -1318,7 +1320,7 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
{
break;
}
//NEEDS Change in CSS
/*bool is_selected = false;
// if we're in move-mode, we may only draw
@@ -1358,8 +1360,8 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
for( int i = 0; i < ( it + 1 ).key() - it.key(); i++ )
{ path.lineTo( QPointF( xCoordOfTick( it.key() + i ), yCoordOfLevel( values[i] ) ) );
//NEEDS Change in CSS
//drawLevelTick( p, it.key() + i, values[i], is_selected );
//drawLevelTick( p, it.key() + i, values[i], is_selected );
}
path.lineTo( QPointF( xCoordOfTick( ( it + 1 ).key() ), yCoordOfLevel( nextValue ) ) );
path.lineTo( QPointF( xCoordOfTick( ( it + 1 ).key() ), yCoordOfLevel( 0 ) ) );
@@ -1535,12 +1537,12 @@ void AutomationEditor::drawLevelTick(QPainter & p, int tick, float value)
p.fillRect( x, y_start, rect_width, rect_height, currentColor );
}
else
{
printf("not in range\n");
}
}
@@ -1598,12 +1600,12 @@ void AutomationEditor::wheelEvent(QWheelEvent * we )
{
y++;
}
if( we->delta() < 0 )
else if( we->delta() < 0 )
{
y--;
}
y = qBound( 0, y, m_zoomingYModel.size() - 1 );
m_zoomingYModel.setValue( y );
m_zoomingYModel.setValue( y );
}
else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::AltModifier )
{
@@ -1612,7 +1614,7 @@ void AutomationEditor::wheelEvent(QWheelEvent * we )
{
q--;
}
if( we->delta() < 0 )
else if( we->delta() < 0 )
{
q++;
}
@@ -1624,13 +1626,13 @@ void AutomationEditor::wheelEvent(QWheelEvent * we )
{
int x = m_zoomingXModel.value();
if( we->delta() > 0 )
{
x--;
}
if( we->delta() < 0 )
{
x++;
}
else if( we->delta() < 0 )
{
x--;
}
x = qBound( 0, x, m_zoomingXModel.size() - 1 );
m_zoomingXModel.setValue( x );
}

View File

@@ -237,7 +237,7 @@ void BBTrackContainerView::removeBBView(int bb)
void BBTrackContainerView::saveSettings(QDomDocument& doc, QDomElement& element)
{
MainWindow::saveWidgetState(parentWidget(), element, QSize( 640, 400 ) );
MainWindow::saveWidgetState( parentWidget(), element );
}
void BBTrackContainerView::loadSettings(const QDomElement& element)

View File

@@ -143,7 +143,7 @@ PianoRoll::PianoRollKeyTypes PianoRoll::prKeyOrder[] =
const int DEFAULT_PR_PPT = KEY_LINE_HEIGHT * DefaultStepsPerTact;
const QVector<double> PianoRoll::m_zoomLevels =
{ 8.0f, 4.0f, 2.0f, 1.0f, 0.5f, 0.25f, 0.125f };
{ 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f };
PianoRoll::PianoRoll() :
@@ -805,7 +805,7 @@ void PianoRoll::setBackgroundShade( const QColor & c )
void PianoRoll::drawNoteRect( QPainter & p, int x, int y,
void PianoRoll::drawNoteRect( QPainter & p, int x, int y,
int width, const Note * n, const QColor & noteCol,
const QColor & selCol, const int noteOpc, const bool borders )
{
@@ -997,6 +997,7 @@ void PianoRoll::shiftPos( int amount ) //shift notes pos by amount
}
m_pattern->rearrangeAllNotes();
m_pattern->updateLength();
m_pattern->dataChanged();
// we modified the song
@@ -1917,7 +1918,7 @@ void PianoRoll::mouseReleaseEvent( QMouseEvent * me )
{
// select the notes within the selection rectangle and
// then destroy the selection rectangle
computeSelectedNotes(
computeSelectedNotes(
me->modifiers() & Qt::ShiftModifier );
}
else if( m_action == ActionMoveNote )
@@ -2459,15 +2460,10 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl )
note->setPos( MidiTime( pos_ticks ) );
note->setKey( key_num );
// If dragging beat notes check if pattern should be MelodyPattern
if( note->length() < 0 )
{
m_pattern->checkType();
}
}
}
}
}
}
else if (m_action == ActionResizeNote)
{
// When resizing notes:
@@ -2475,7 +2471,7 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl )
// If shift is pressed we resize and rearrange only the selected notes
// If shift + ctrl then we also rearrange all posterior notes (sticky)
// If shift is pressed but only one note is selected, apply sticky
if (shift)
{
// Algorithm:
@@ -2495,8 +2491,8 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl )
const Note *posteriorNote = nullptr;
for (const Note *note : notes)
{
if (note->selected() && (posteriorNote == nullptr ||
note->oldPos().getTicks() + note->oldLength().getTicks() >
if (note->selected() && (posteriorNote == nullptr ||
note->oldPos().getTicks() + note->oldLength().getTicks() >
posteriorNote->oldPos().getTicks() + posteriorNote->oldLength().getTicks()))
{
posteriorNote = note;
@@ -2516,9 +2512,9 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl )
if(note->selected())
{
// scale relative start and end positions by scaleFactor
int newStart = stretchStartTick + scaleFactor *
int newStart = stretchStartTick + scaleFactor *
(note->oldPos().getTicks() - stretchStartTick);
int newEnd = stretchStartTick + scaleFactor *
int newEnd = stretchStartTick + scaleFactor *
(note->oldPos().getTicks()+note->oldLength().getTicks() - stretchStartTick);
// if not holding alt, quantize the offsets
if(!alt)
@@ -2537,7 +2533,7 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl )
int newLength = qMax(1, newEnd-newStart);
if (note == posteriorNote)
{
posteriorDeltaThisFrame = (newStart+newLength) -
posteriorDeltaThisFrame = (newStart+newLength) -
(note->pos().getTicks() + note->length().getTicks());
}
note->setLength( MidiTime(newLength) );
@@ -2892,18 +2888,20 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
++key;
}
// Draw alternating shades on bars
// count the bars which disappear on left by scrolling
float timeSignature = static_cast<float>( Engine::getSong()->getTimeSigModel().getNumerator() )
/ static_cast<float>( Engine::getSong()->getTimeSigModel().getDenominator() );
float zoomFactor = m_zoomLevels[m_zoomingModel.value()];
int barCount = m_currentPosition / MidiTime::ticksPerTact();
int leftBars = m_currentPosition * zoomFactor / m_ppt;
//the bars which disappears at the left side by scrolling
int leftBars = m_currentPosition * zoomFactor / MidiTime::ticksPerTact();
for( int x = WHITE_KEY_WIDTH; x < width() + m_currentPosition * zoomFactor; x += m_ppt, ++barCount )
//iterates the visible bars and draw the shading on uneven bars
for( int x = WHITE_KEY_WIDTH, barCount = leftBars; x < width() + m_currentPosition * zoomFactor / timeSignature; x += m_ppt, ++barCount )
{
if( ( barCount + leftBars ) % 2 != 0 )
{
p.fillRect( x - m_currentPosition * zoomFactor, PR_TOP_MARGIN, m_ppt,
p.fillRect( x - m_currentPosition * zoomFactor / timeSignature, PR_TOP_MARGIN, m_ppt,
height() - ( PR_BOTTOM_MARGIN + PR_TOP_MARGIN ), backgroundShade() );
}
}
@@ -3258,7 +3256,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we )
{
q--;
}
if( we->delta() < 0 )
else if( we->delta() < 0 )
{
q++;
}
@@ -3272,7 +3270,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we )
{
l--;
}
if( we->delta() < 0 )
else if( we->delta() < 0 )
{
l++;
}
@@ -3283,13 +3281,13 @@ void PianoRoll::wheelEvent(QWheelEvent * we )
{
int z = m_zoomingModel.value();
if( we->delta() > 0 )
{
z--;
}
if( we->delta() < 0 )
{
z++;
}
else if( we->delta() < 0 )
{
z--;
}
z = qBound( 0, z, m_zoomingModel.size() - 1 );
// update combobox with zooming-factor
m_zoomingModel.setValue( z );
@@ -3920,27 +3918,32 @@ int PianoRoll::quantization() const
void PianoRoll::quantizeNotes()
{
if( ! hasValidPattern() )
{
return;
}
NoteVector notes = getSelectedNotes();
if (notes.empty())
if( notes.empty() )
{
for (Note* n : m_pattern->notes())
for( Note* n : m_pattern->notes() )
{
notes.push_back(n);
notes.push_back( n );
}
}
for (Note* n : notes)
for( Note* n : notes )
{
if (n->length() == MidiTime(0))
if( n->length() == MidiTime( 0 ) )
{
continue;
}
Note copy(*n);
m_pattern->removeNote(n);
copy.quantizePos(quantization());
m_pattern->addNote(copy);
m_pattern->removeNote( n );
copy.quantizePos( quantization() );
m_pattern->addNote( copy );
}
update();
@@ -4389,7 +4392,7 @@ void PianoRollWindow::reset()
void PianoRollWindow::saveSettings( QDomDocument & doc, QDomElement & de )
{
MainWindow::saveWidgetState( this, de, QSize( 640, 480 ) );
MainWindow::saveWidgetState( this, de );
}

View File

@@ -71,7 +71,7 @@ void positionLine::paintEvent( QPaintEvent * pe )
}
const QVector<double> SongEditor::m_zoomLevels =
{ 16.0f, 8.0f, 4.0f, 2.0f, 1.0f, 0.5f, 0.25f, 0.125f };
{ 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f, 16.0f };
SongEditor::SongEditor( Song * song ) :
@@ -262,7 +262,7 @@ SongEditor::~SongEditor()
void SongEditor::saveSettings( QDomDocument& doc, QDomElement& element )
{
MainWindow::saveWidgetState(parentWidget(), element, QSize( 640, 400 ));
MainWindow::saveWidgetState( parentWidget(), element );
}
void SongEditor::loadSettings( const QDomElement& element )
@@ -360,13 +360,13 @@ void SongEditor::wheelEvent( QWheelEvent * we )
int z = m_zoomingModel->value();
if( we->delta() > 0 )
{
z--;
}
if( we->delta() < 0 )
{
z++;
}
else if( we->delta() < 0 )
{
z--;
}
z = qBound( 0, z, m_zoomingModel->size() - 1 );
// update combobox with zooming-factor
m_zoomingModel->setValue( z );
@@ -586,6 +586,14 @@ void SongEditor::updatePosition( const MidiTime & t )
void SongEditor::updatePositionLine()
{
m_positionLine->setFixedHeight( height() );
}
void SongEditor::zoomingChanged()
{
setPixelsPerTact( m_zoomLevels[m_zoomingModel->value()] * DEFAULT_PIXELS_PER_TACT );
@@ -697,6 +705,7 @@ SongEditorWindow::SongEditorWindow(Song* song) :
zoomToolBar->addWidget( m_zoomingComboBox );
connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad()));
connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine()));
}
QSize SongEditorWindow::sizeHint() const
@@ -705,6 +714,14 @@ QSize SongEditorWindow::sizeHint() const
}
void SongEditorWindow::resizeEvent(QResizeEvent *event)
{
emit resized();
}
void SongEditorWindow::play()
{
emit playTriggered();

View File

@@ -102,7 +102,7 @@ ControllerRackView::~ControllerRackView()
void ControllerRackView::saveSettings( QDomDocument & _doc,
QDomElement & _this )
{
MainWindow::saveWidgetState( this, _this, QSize( 400, 300) );
MainWindow::saveWidgetState( this, _this );
}

View File

@@ -39,7 +39,7 @@ EffectRackView::EffectRackView( EffectChain* model, QWidget* parent ) :
ModelView( NULL, this )
{
QVBoxLayout* mainLayout = new QVBoxLayout( this );
mainLayout->setMargin( 0 );
mainLayout->setMargin( 5 );
m_effectsGroupBox = new GroupBox( tr( "EFFECTS CHAIN" ) );
mainLayout->addWidget( m_effectsGroupBox );

View File

@@ -41,8 +41,6 @@ GroupBox::GroupBox( const QString & _caption, QWidget * _parent ) :
m_caption( _caption ),
m_titleBarHeight( 11 )
{
updatePixmap();
m_led = new PixmapButton( this, _caption );
m_led->setCheckable( true );
m_led->move( 3, 0 );
@@ -84,60 +82,22 @@ void GroupBox::mousePressEvent( QMouseEvent * _me )
void GroupBox::resizeEvent( QResizeEvent * _ev )
void GroupBox::paintEvent( QPaintEvent * pe )
{
updatePixmap();
QWidget::resizeEvent( _ev );
}
QPainter p( this );
void GroupBox::updatePixmap()
{
QColor bg_color = QApplication::palette().color( QPalette::Active,
QPalette::Background );
QPixmap pm( size() );
pm.fill( bg_color/*.dark( 132 )*/ );
QPainter p( &pm );
// Draw background
p.fillRect( 0, 0, width() - 1, height() - 1, p.background() );
// outer rect
p.setPen( bg_color.dark( 150 ) );
p.setPen( p.background().color().dark( 150 ) );
p.drawRect( 0, 0, width() - 1, height() - 1 );
// brighter line at bottom/right
p.setPen( bg_color.light( 150 ) );
p.drawLine( width() - 1, 0, width() - 1, height() - 1 );
p.drawLine( 0, height() - 1, width() - 1, height() - 1 );
// draw groupbox-titlebar
QLinearGradient g( 0, 0, 0, m_titleBarHeight );
g.setColorAt( 0, bg_color.darker( 250 ) );
g.setColorAt( 0.1, bg_color.lighter( 120 ) );
g.setColorAt( 1, bg_color.darker( 250 ) );
p.fillRect( 2, 2, width() - 4, m_titleBarHeight, g );
// draw line below titlebar
p.setPen( bg_color.dark( 400 ) );
p.drawLine( 1, m_titleBarHeight + 1, width() - 3, m_titleBarHeight + 1 );
p.fillRect( 1, 1, width() - 2, m_titleBarHeight + 1, p.background().color().darker( 150 ) );
// black inner rect
p.drawRect( 1, 1, width() - 3, height() - 3 );
//p.setPen( QColor( 255, 255, 255 ) );
// draw text
p.setPen( palette().color( QPalette::Active, QPalette::Text ) );
p.setFont( pointSize<8>( font() ) );
p.drawText( 22, m_titleBarHeight, m_caption );
QPalette pal = palette();
pal.setBrush( backgroundRole(), QBrush( pm ) );
setPalette( pal );
}

View File

@@ -76,7 +76,8 @@ InstrumentSoundShapingView::InstrumentSoundShapingView( QWidget * _parent ) :
{
m_envLfoViews[i] = new EnvelopeAndLfoView( m_targetsTabWidget );
m_targetsTabWidget->addTab( m_envLfoViews[i],
tr( InstrumentSoundShaping::targetNames[i][0].toUtf8().constData() ) );
tr( InstrumentSoundShaping::targetNames[i][0].toUtf8().constData() ),
NULL );
}

View File

@@ -631,7 +631,6 @@ void Knob::mouseMoveEvent( QMouseEvent * _me )
emit sliderMoved( model()->value() );
QCursor::setPos( mapToGlobal( m_origMousePos ) );
}
s_textFloat->setText( displayValue() );
}
@@ -735,7 +734,7 @@ void Knob::setPosition( const QPoint & _p )
float newValue = value * ratio;
if( qAbs( newValue ) >= step )
{
float roundedValue = static_cast<float>( static_cast<int>( ( oldValue - newValue ) / step + 0.5 ) ) * step;
float roundedValue = qRound( ( oldValue - value ) / step ) * step;
model()->setValue( roundedValue );
m_leftOver = 0.0f;
}
@@ -749,7 +748,7 @@ void Knob::setPosition( const QPoint & _p )
{
if( qAbs( value ) >= step )
{
float roundedValue = static_cast<float>( static_cast<int>( ( oldValue - value ) / step + 0.5 ) ) * step;
float roundedValue = qRound( ( oldValue - value ) / step ) * step;
model()->setValue( roundedValue );
m_leftOver = 0.0f;
}

View File

@@ -67,7 +67,7 @@ ProjectNotes::ProjectNotes() :
setupActions();
setCentralWidget( m_edit );
setWindowTitle( tr( "Project notes" ) );
setWindowTitle( tr( "Project Notes" ) );
setWindowIcon( embed::getIconPixmap( "project_notes" ) );
gui->mainWindow()->addWindowedWidget( this );
@@ -89,7 +89,7 @@ ProjectNotes::~ProjectNotes()
void ProjectNotes::clear()
{
m_edit->setHtml( tr( "Put down your project notes here." ) );
m_edit->setHtml( tr( "Enter project notes here" ) );
m_edit->selectAll();
m_edit->setTextColor( QColor( 224, 224, 224 ) );
QTextCursor cursor = m_edit->textCursor();
@@ -438,7 +438,7 @@ void ProjectNotes::alignmentChanged( int _a )
void ProjectNotes::saveSettings( QDomDocument & _doc, QDomElement & _this )
{
MainWindow::saveWidgetState( this, _this, QSize( 640, 400 ) );
MainWindow::saveWidgetState( this, _this );
QDomCDATASection ds = _doc.createCDATASection( m_edit->toHtml() );
_this.appendChild( ds );

View File

@@ -2,7 +2,7 @@
* TabWidget.cpp - tabwidget for LMMS
*
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
@@ -27,53 +27,71 @@
#include <QMouseEvent>
#include <QPainter>
#include <QPixmap>
#include <QToolTip>
#include <QWheelEvent>
#include "gui_templates.h"
#include "embed.h"
TabWidget::TabWidget( const QString & _caption, QWidget * _parent ) :
QWidget( _parent ),
TabWidget::TabWidget( const QString & caption, QWidget * parent, bool usePixmap ) :
QWidget( parent ),
m_activeTab( 0 ),
m_caption( _caption ),
m_tabheight( _caption.isEmpty() ? 11: 10 )
m_caption( caption ),
m_usePixmap( usePixmap ),
m_tabText( 0, 0, 0 ),
m_tabTitleText( 0, 0, 0 ),
m_tabSelected( 0, 0, 0 ),
m_tabBackground( 0, 0, 0 ),
m_tabBorder( 0, 0, 0 )
{
// Create taller tabbar when it's to display artwork tabs
m_tabbarHeight = usePixmap ? GRAPHIC_TAB_HEIGHT : TEXT_TAB_HEIGHT;
m_tabheight = caption.isEmpty() ? m_tabbarHeight - 3 : m_tabbarHeight - 4;
setFont( pointSize<8>( font() ) );
setAutoFillBackground( true );
QColor bg_color = QApplication::palette().color( QPalette::Active,
QPalette::Background ).
darker( 132 );
QColor bg_color = QApplication::palette().color( QPalette::Active, QPalette::Background ). darker( 132 );
QPalette pal = palette();
pal.setColor( QPalette::Background, bg_color );
setPalette( pal );
}
TabWidget::~TabWidget()
{
}
void TabWidget::addTab( QWidget * _w, const QString & _name, int _idx )
void TabWidget::addTab( QWidget * w, const QString & name, const char *pixmap, int idx )
{
setFont( pointSize<8>( font() ) );
widgetDesc d = { _w, _name, fontMetrics().width( _name ) + 10 } ;
if( _idx < 0/* || m_widgets.contains( _idx ) == true*/ )
// Append tab when position is not given
if( idx < 0/* || m_widgets.contains( idx ) == true*/ )
{
while( m_widgets.contains( ++_idx ) == true )
while( m_widgets.contains( ++idx ) == true )
{
}
}
m_widgets[_idx] = d;
_w->setFixedSize( width() - 4, height() - 14 );
_w->move( 2, 13 );
_w->hide();
// Tab's width when it is a text tab. This isn't correct for artwork tabs, but it's fixed later during the PaintEvent
int tab_width = fontMetrics().width( name ) + 10;
// Register new tab
widgetDesc d = { w, pixmap, name, tab_width };
m_widgets[idx] = d;
// Position tab's window
w->setFixedSize( width() - 4, height() - m_tabbarHeight );
w->move( 2, m_tabbarHeight - 1 );
w->hide();
// Show tab's window if it's active
if( m_widgets.contains( m_activeTab ) )
{
// make sure new tab doesn't overlap current widget
@@ -85,15 +103,15 @@ void TabWidget::addTab( QWidget * _w, const QString & _name, int _idx )
void TabWidget::setActiveTab( int _idx )
void TabWidget::setActiveTab( int idx )
{
if( m_widgets.contains( _idx ) )
if( m_widgets.contains( idx ) )
{
int old_active = m_activeTab;
m_activeTab = _idx;
m_activeTab = idx;
m_widgets[m_activeTab].w->raise();
m_widgets[m_activeTab].w->show();
if( old_active != _idx && m_widgets.contains( old_active ) )
if( old_active != idx && m_widgets.contains( old_active ) )
{
m_widgets[old_active].w->hide();
}
@@ -102,27 +120,74 @@ void TabWidget::setActiveTab( int _idx )
}
void TabWidget::mousePressEvent( QMouseEvent * _me )
// Return the index of the tab at position "pos"
int TabWidget::findTabAtPos( const QPoint *pos )
{
if( _me->y() > 1 && _me->y() < 13 )
if( pos->y() > 1 && pos->y() < m_tabbarHeight - 1 )
{
int cx = ( ( m_caption == "" ) ? 4 : 14 ) +
fontMetrics().width( m_caption );
for( widgetStack::iterator it = m_widgets.begin();
it != m_widgets.end(); ++it )
int cx = ( ( m_caption == "" ) ? 4 : 14 ) + fontMetrics().width( m_caption );
for( widgetStack::iterator it = m_widgets.begin(); it != m_widgets.end(); ++it )
{
if( _me->x() >= cx &&
_me->x() <= cx + ( *it ).nwidth )
if( pos->x() >= cx && pos->x() <= cx + ( *it ).nwidth )
{
setActiveTab( it.key() );
update();
return;
return( it.key() );
}
cx += ( *it ).nwidth;
}
}
// Haven't found any tab at position "pos"
return( -1 );
}
// Overload the QWidget::event handler to display tooltips (from https://doc.qt.io/qt-4.8/qt-widgets-tooltips-example.html)
bool TabWidget::event(QEvent *event)
{
if ( event->type() == QEvent::ToolTip )
{
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
int idx = findTabAtPos( & helpEvent->pos() );
if ( idx != -1 )
{
// Display tab's tooltip
QToolTip::showText( helpEvent->globalPos(), m_widgets[idx].name );
}
else
{
// The tooltip event doesn't relate to any tab, let's ignore it
QToolTip::hideText();
event->ignore();
}
return true;
}
// not a Tooltip event, let's propagate it to the other event handlers
return QWidget::event(event);
}
// Activate tab when clicked
void TabWidget::mousePressEvent( QMouseEvent * me )
{
// Find index of tab that has been clicked
QPoint pos = me->pos();
int idx = findTabAtPos( &pos );
// When found, activate tab that has been clicked
if ( idx != -1 )
{
setActiveTab( idx );
update();
return;
}
}
@@ -133,7 +198,7 @@ void TabWidget::resizeEvent( QResizeEvent * )
for( widgetStack::iterator it = m_widgets.begin();
it != m_widgets.end(); ++it )
{
( *it ).w->setFixedSize( width() - 4, height() - 14 );
( *it ).w->setFixedSize( width() - 4, height() - m_tabbarHeight );
}
}
@@ -141,66 +206,77 @@ void TabWidget::resizeEvent( QResizeEvent * )
void TabWidget::paintEvent( QPaintEvent * _pe )
void TabWidget::paintEvent( QPaintEvent * pe )
{
setFont( pointSize<8>( font() ) );
QPainter p( this );
p.setFont( pointSize<7>( font() ) );
QColor bg_color = QApplication::palette().color( QPalette::Active,
QPalette::Background );
QLinearGradient g( 0, 0, 0, m_tabheight );
g.setColorAt( 0, bg_color.darker( 250 ) );
g.setColorAt( 0.1, bg_color.lighter( 120 ) );
g.setColorAt( 1, bg_color.darker( 250 ) );
// Draw background
QBrush bg_color = p.background();
p.fillRect( 0, 0, width() - 1, height() - 1, bg_color );
bool big_tab_captions = ( m_caption == "" );
p.setPen( bg_color.darker( 150 ) );
// Draw external borders
p.setPen( tabBorder() );
p.drawRect( 0, 0, width() - 1, height() - 1 );
p.setPen( bg_color.light( 150 ) );
p.drawLine( width() - 1, 0, width() - 1, height() - 1 );
p.drawLine( 0, height() - 1, width() - 1, height() - 1 );
p.setPen( QColor( 0, 0, 0 ) );
p.drawRect( 1, 1, width() - 3, height() - 3 );
p.fillRect( 2, 2, width() - 4, m_tabheight, g );
p.drawLine( 2, m_tabheight + 2, width() - 3, m_tabheight + 2);
// Draw tabs' bar background
p.fillRect( 1, 1, width() - 2, m_tabheight + 2, tabBackground() );
// Draw title, if any
if( ! m_caption.isEmpty() )
{
p.setPen( QColor( 255, 255, 255 ) );
p.setFont( pointSize<8>( p.font() ) );
p.setPen( tabTitleText() );
p.drawText( 5, 11, m_caption );
}
// Calculate the tabs' x (tabs are painted next to the caption)
int tab_x_offset = m_caption.isEmpty() ? 4 : 14 + fontMetrics().width( m_caption );
QColor cap_col( 160, 160, 160 );
if( big_tab_captions )
// Compute tabs' width depending on the number of tabs (only applicable for artwork tabs)
widgetStack::iterator first = m_widgets.begin();
widgetStack::iterator last = m_widgets.end();
int tab_width = width();
if ( first != last )
{
p.setFont( pointSize<8>( p.font() ) );
cap_col = QColor( 224, 224, 224 );
tab_width = ( width() - tab_x_offset ) / std::distance( first, last );
}
else
{
p.setFont( pointSize<7>( p.font() ) );
}
p.setPen( cap_col );
for( widgetStack::iterator it = m_widgets.begin();
it != m_widgets.end(); ++it )
// Draw all tabs
p.setPen( tabText() );
for( widgetStack::iterator it = first ; it != last ; ++it )
{
if( it.key() == m_activeTab )
// Draw a text tab or a artwork tab.
if( m_usePixmap )
{
p.setPen( QColor( 32, 48, 64 ) );
p.fillRect( tab_x_offset, 2, ( *it ).nwidth - 6, 10, cap_col );
// Fixes tab's width, because original size is only correct for text tabs
( *it ).nwidth = tab_width;
// Get artwork
QPixmap artwork( embed::getIconPixmap( ( *it ).pixmap ) );
// Highlight active tab
if( it.key() == m_activeTab )
{
p.fillRect( tab_x_offset, 0, ( *it ).nwidth, m_tabbarHeight - 1, tabSelected() );
}
// Draw artwork
p.drawPixmap(tab_x_offset + ( ( *it ).nwidth - artwork.width() ) / 2, 1, artwork );
}
p.drawText( tab_x_offset + 3, m_tabheight, ( *it ).name );
p.setPen( cap_col );
else
{
// Highlight tab when active
if( it.key() == m_activeTab )
{
p.fillRect( tab_x_offset, 2, ( *it ).nwidth - 6, m_tabbarHeight - 4, tabSelected() );
}
// Draw text
p.drawText( tab_x_offset + 3, m_tabheight + 1, ( *it ).name );
}
// Next tab's horizontal position
tab_x_offset += ( *it ).nwidth;
}
}
@@ -208,13 +284,16 @@ void TabWidget::paintEvent( QPaintEvent * _pe )
void TabWidget::wheelEvent( QWheelEvent * _we )
// Switch between tabs with mouse wheel
void TabWidget::wheelEvent( QWheelEvent * we )
{
if (_we->y() > m_tabheight)
if( we->y() > m_tabheight )
{
return;
}
_we->accept();
int dir = ( _we->delta() < 0 ) ? 1 : -1;
we->accept();
int dir = ( we->delta() < 0 ) ? 1 : -1;
int tab = m_activeTab;
while( tab > -1 && static_cast<int>( tab ) < m_widgets.count() )
{
@@ -227,9 +306,62 @@ void TabWidget::wheelEvent( QWheelEvent * _we )
setActiveTab( tab );
}
// Return the color to be used to draw a TabWidget's title text (if any)
QColor TabWidget::tabTitleText() const
{
return m_tabTitleText;
}
// Set the color to be used to draw a TabWidget's title text (if any)
void TabWidget::setTabTitleText( const QColor & c )
{
m_tabTitleText = c;
}
// Return the color to be used to draw a TabWidget's text (if any)
QColor TabWidget::tabText() const
{
return m_tabText;
}
// Set the color to be used to draw a TabWidget's text (if any)
void TabWidget::setTabText( const QColor & c )
{
m_tabText = c;
}
// Return the color to be used to highlight a TabWidget'selected tab (if any)
QColor TabWidget::tabSelected() const
{
return m_tabSelected;
}
// Set the color to be used to highlight a TabWidget'selected tab (if any)
void TabWidget::setTabSelected( const QColor & c )
{
m_tabSelected = c;
}
// Return the color to be used for the TabWidget's background
QColor TabWidget::tabBackground() const
{
return m_tabBackground;
}
// Set the color to be used for the TabWidget's background
void TabWidget::setTabBackground( const QColor & c )
{
m_tabBackground = c;
}
// Return the color to be used for the TabWidget's borders
QColor TabWidget::tabBorder() const
{
return m_tabBorder;
}
// Set the color to be used for the TabWidget's borders
void TabWidget::setTabBorder( const QColor & c )
{
m_tabBorder = c;
}

View File

@@ -36,6 +36,7 @@
#include "InstrumentTrack.h"
#include "RenameDialog.h"
#include "Song.h"
#include "TrackRenameLineEdit.h"
@@ -48,7 +49,7 @@ TrackLabelButton::TrackLabelButton( TrackView * _tv, QWidget * _parent ) :
setAcceptDrops( true );
setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) );
setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
m_renameLineEdit = new QLineEdit( this );
m_renameLineEdit = new TrackRenameLineEdit( this );
m_renameLineEdit->hide();
if( ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt() )
@@ -83,8 +84,8 @@ void TrackLabelButton::rename()
if( ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt() )
{
QString txt = m_trackView->getTrack()->name();
RenameDialog rename_dlg( txt );
rename_dlg.exec();
RenameDialog renameDlg( txt );
renameDlg.exec();
if( txt != text() )
{
m_trackView->getTrack()->setName( txt );

View File

@@ -0,0 +1,61 @@
/*
* TrackRenameLineEdit.cpp - implementation of class TrackRenameLineEdit, which
* represents the text field that appears when one
* double-clicks a track's label to rename it
*
* Copyright (c) 2004-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2017 Alexandre Almeida <http://m374lx.users.sourceforge.net/>
*
* This file is part of LMMS - https://lmms.io
*
* 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 "TrackRenameLineEdit.h"
#include <QKeyEvent>
TrackRenameLineEdit::TrackRenameLineEdit( QWidget * parent ) :
QLineEdit( parent )
{
}
void TrackRenameLineEdit::show()
{
m_oldName = text();
QLineEdit::show();
}
void TrackRenameLineEdit::keyPressEvent( QKeyEvent * ke )
{
if( ke->key() == Qt::Key_Escape )
{
setText( m_oldName );
hide();
}
QLineEdit::keyPressEvent( ke );
}

View File

@@ -11,6 +11,7 @@
#cmakedefine LMMS_HAVE_ALSA
#cmakedefine LMMS_HAVE_FLUIDSYNTH
#cmakedefine LMMS_HAVE_JACK
#cmakedefine LMMS_HAVE_MP3LAME
#cmakedefine LMMS_HAVE_OGGVORBIS
#cmakedefine LMMS_HAVE_OSS
#cmakedefine LMMS_HAVE_SNDIO

View File

@@ -1411,8 +1411,8 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
generalSettingsLayout->addLayout( basicControlsLayout );
m_tabWidget = new TabWidget( "", this );
m_tabWidget->setFixedHeight( INSTRUMENT_HEIGHT + 10 );
m_tabWidget = new TabWidget( "", this, true );
m_tabWidget->setFixedHeight( INSTRUMENT_HEIGHT + GRAPHIC_TAB_HEIGHT - 4 );
// create tab-widgets
@@ -1439,11 +1439,11 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
m_miscView = new InstrumentMiscView( m_track, m_tabWidget );
m_tabWidget->addTab( m_ssView, tr( "ENV/LFO" ), 1 );
m_tabWidget->addTab( instrumentFunctions, tr( "FUNC" ), 2 );
m_tabWidget->addTab( m_effectView, tr( "FX" ), 3 );
m_tabWidget->addTab( m_midiView, tr( "MIDI" ), 4 );
m_tabWidget->addTab( m_miscView, tr( "MISC" ), 5 );
m_tabWidget->addTab( m_ssView, tr( "Envelope, filter & LFO" ), "env_lfo_tab", 1 );
m_tabWidget->addTab( instrumentFunctions, tr( "Chord stacking & arpeggio" ), "func_tab", 2 );
m_tabWidget->addTab( m_effectView, tr( "Effects" ), "fx_tab", 3 );
m_tabWidget->addTab( m_midiView, tr( "MIDI settings" ), "midi_tab", 4 );
m_tabWidget->addTab( m_miscView, tr( "Miscellaneous" ), "misc_tab", 5 );
// setup piano-widget
m_pianoView = new PianoView( this );
@@ -1617,7 +1617,7 @@ void InstrumentTrackWindow::updateInstrumentView()
if( m_track->m_instrument != NULL )
{
m_instrumentView = m_track->m_instrument->createView( m_tabWidget );
m_tabWidget->addTab( m_instrumentView, tr( "PLUGIN" ), 0 );
m_tabWidget->addTab( m_instrumentView, tr( "Plugin" ), "plugin_tab", 0 );
m_tabWidget->setActiveTab( 0 );
m_ssView->setFunctionsHidden( m_track->m_instrument->flags().testFlag( Instrument::IsSingleStreamed ) );

View File

@@ -361,9 +361,7 @@ void Pattern::checkType()
NoteVector::Iterator it = m_notes.begin();
while( it != m_notes.end() )
{
if( ( *it )->length() > 0 ||
( *it )->pos() % ( MidiTime::ticksPerTact() /
MidiTime::stepsPerTact() ) )
if( ( *it )->length() > 0 )
{
setType( MelodyPattern );
return;

View File

@@ -71,6 +71,8 @@ SampleTCO::SampleTCO( Track * _track ) :
{
connect( timeLine, SIGNAL( positionMarkerMoved() ), this, SLOT( playbackPositionChanged() ) );
}
//playbutton clicked or space key / on Export Song set isPlaying to false
connect( Engine::getSong(), SIGNAL( playbackStateChanged() ), this, SLOT( playbackPositionChanged() ) );
//care about loops
connect( Engine::getSong(), SIGNAL( updateSampleTracks() ), this, SLOT( playbackPositionChanged() ) );
//care about mute TCOs
@@ -79,11 +81,6 @@ SampleTCO::SampleTCO( Track * _track ) :
connect( getTrack()->getMutedModel(), SIGNAL( dataChanged() ),this, SLOT( playbackPositionChanged() ) );
//care about TCO position
connect( this, SIGNAL( positionChanged() ), this, SLOT( updateTrackTcos() ) );
//playbutton clicked or space key
if( gui )
{
connect( gui->songEditor(), SIGNAL( playTriggered() ), this, SLOT( playbackPositionChanged() ) );
}
switch( getTrack()->trackContainer()->type() )
{
@@ -148,7 +145,7 @@ void SampleTCO::setSampleBuffer( SampleBuffer* sb )
void SampleTCO::setSampleFile( const QString & _sf )
{
m_sampleBuffer->setAudioFile( _sf );
updateLength();
changeLength( (int) ( m_sampleBuffer->frames() / Engine::framesPerTick() ) );
emit sampleChanged();
emit playbackPositionChanged();
@@ -169,7 +166,8 @@ void SampleTCO::toggleRecord()
void SampleTCO::playbackPositionChanged()
{
Engine::mixer()->removePlayHandlesOfTypes( getTrack(), PlayHandle::TypeSamplePlayHandle );
m_isPlaying = false;
SampleTrack * st = dynamic_cast<SampleTrack*>( getTrack() );
st->setPlayingTcos( false );
}
@@ -199,7 +197,7 @@ void SampleTCO::setIsPlaying(bool isPlaying)
void SampleTCO::updateLength()
{
changeLength( sampleLength() );
emit sampleChanged();
}
@@ -505,12 +503,6 @@ void SampleTCOView::paintEvent( QPaintEvent * pe )
// disable antialiasing for borders, since its not needed
p.setRenderHint( QPainter::Antialiasing, false );
if( r.width() < width() - 1 )
{
p.drawLine( r.x(), r.y() + r.height() / 2,
rect().right() - TCO_BORDER_WIDTH, r.y() + r.height() / 2 );
}
// inner border
p.setPen( c.lighter( 160 ) );
p.drawRect( 1, 1, rect().right() - TCO_BORDER_WIDTH,
@@ -716,12 +708,21 @@ void SampleTrack::loadTrackSpecificSettings( const QDomElement & _this )
void SampleTrack::updateTcos()
{
Engine::mixer()->removePlayHandlesOfTypes( this, PlayHandle::TypeSamplePlayHandle );
setPlayingTcos( false );
}
void SampleTrack::setPlayingTcos( bool isPlaying )
{
for( int i = 0; i < numOfTCOs(); ++i )
{
TrackContentObject * tco = getTCO( i );
SampleTCO * sTco = dynamic_cast<SampleTCO*>( tco );
sTco->playbackPositionChanged();
sTco->setIsPlaying( isPlaying );
}
}