Merge branch 'stable-1.2' into master (@liushuyu)
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -113,6 +113,7 @@ void LfoController::updateValueBuffer()
|
||||
}
|
||||
|
||||
m_currentPhase = absFraction( phase - m_phaseOffset );
|
||||
m_bufferLastUpdated = s_periods;
|
||||
}
|
||||
|
||||
void LfoController::updatePhase()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
133
src/core/audio/AudioFileMP3.cpp
Normal file
133
src/core/audio/AudioFileMP3.cpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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() )
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -102,7 +102,7 @@ ControllerRackView::~ControllerRackView()
|
||||
void ControllerRackView::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _this )
|
||||
{
|
||||
MainWindow::saveWidgetState( this, _this, QSize( 400, 300) );
|
||||
MainWindow::saveWidgetState( this, _this );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
61
src/gui/widgets/TrackRenameLineEdit.cpp
Normal file
61
src/gui/widgets/TrackRenameLineEdit.cpp
Normal 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 );
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 ) );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user