Merge branch 'stable-1.2'
# Conflicts: # data/locale/cs.ts # data/locale/en.ts # data/locale/ko.ts # data/locale/ru.ts # data/locale/uk.ts # data/locale/zh_TW.ts # include/Engine.h # plugins/nes/Nes.cpp # src/core/NotePlayHandle.cpp # src/core/SampleBuffer.cpp # src/tracks/SampleTrack.cpp
This commit is contained in:
@@ -781,6 +781,16 @@ void AutomationPattern::resolveAllIDs()
|
||||
{
|
||||
a->addObject( dynamic_cast<AutomatableModel *>( o ), false );
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: Remove this block once the automation system gets fixed
|
||||
// This is a temporary fix for https://github.com/LMMS/lmms/issues/4781
|
||||
o = Engine::projectJournal()->journallingObject(ProjectJournal::idToSave(*k));
|
||||
if( o && dynamic_cast<AutomatableModel *>( o ) )
|
||||
{
|
||||
a->addObject( dynamic_cast<AutomatableModel *>( o ), false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
a->m_idsToResolve.clear();
|
||||
|
||||
@@ -205,13 +205,15 @@ void ControllerConnection::loadSettings( const QDomElement & _this )
|
||||
else
|
||||
{
|
||||
m_controllerId = _this.attribute( "id", "-1" ).toInt();
|
||||
if( m_controllerId < 0 || m_controllerId >= Engine::getSong()->controllers().size() )
|
||||
if( m_controllerId < 0 )
|
||||
{
|
||||
qWarning( "controller index invalid\n" );
|
||||
m_controllerId = -1;
|
||||
}
|
||||
|
||||
if (!Engine::getSong()->isLoadingProject() && m_controllerId != -1)
|
||||
if (!Engine::getSong()->isLoadingProject()
|
||||
&& m_controllerId != -1
|
||||
&& m_controllerId < Engine::getSong()->controllers().size())
|
||||
{
|
||||
setController( Engine::getSong()->
|
||||
controllers().at( m_controllerId ) );
|
||||
|
||||
@@ -105,6 +105,12 @@ void LmmsCore::destroy()
|
||||
delete ConfigManager::inst();
|
||||
}
|
||||
|
||||
float LmmsCore::framesPerTick(sample_rate_t sample_rate)
|
||||
{
|
||||
return sample_rate * 60.0f * 4 /
|
||||
DefaultTicksPerTact / s_song->getTempo();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -577,21 +577,35 @@ void Mixer::changeQuality( const struct qualitySettings & _qs )
|
||||
|
||||
|
||||
|
||||
void Mixer::setAudioDevice( AudioDevice * _dev,
|
||||
bool startNow )
|
||||
void Mixer::doSetAudioDevice( AudioDevice * _dev )
|
||||
{
|
||||
stopProcessing();
|
||||
// TODO: Use shared_ptr here in the future.
|
||||
// Currently, this is safe, because this is only called by
|
||||
// ProjectRenderer, and after ProjectRenderer calls this function,
|
||||
// it does not access the old device anymore.
|
||||
if( m_audioDev != m_oldAudioDev ) {delete m_audioDev;}
|
||||
|
||||
if( _dev == NULL )
|
||||
if( _dev )
|
||||
{
|
||||
m_audioDev = _dev;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "param _dev == NULL in Mixer::setAudioDevice(...). "
|
||||
"Trying any working audio-device\n" );
|
||||
m_audioDev = tryAudioDevices();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_audioDev = _dev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Mixer::setAudioDevice( AudioDevice * _dev,
|
||||
bool startNow )
|
||||
{
|
||||
stopProcessing();
|
||||
|
||||
doSetAudioDevice( _dev );
|
||||
|
||||
emit sampleRateChanged();
|
||||
|
||||
@@ -601,26 +615,16 @@ void Mixer::setAudioDevice( AudioDevice * _dev,
|
||||
|
||||
|
||||
|
||||
void Mixer::setAudioDevice( AudioDevice * _dev,
|
||||
void Mixer::setAudioDevice(AudioDevice * _dev,
|
||||
const struct qualitySettings & _qs,
|
||||
bool _needs_fifo,
|
||||
bool startNow )
|
||||
bool startNow)
|
||||
{
|
||||
// don't delete the audio-device
|
||||
stopProcessing();
|
||||
|
||||
m_qualitySettings = _qs;
|
||||
|
||||
if( _dev == NULL )
|
||||
{
|
||||
printf( "param _dev == NULL in Mixer::setAudioDevice(...). "
|
||||
"Trying any working audio-device\n" );
|
||||
m_audioDev = tryAudioDevices();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_audioDev = _dev;
|
||||
}
|
||||
doSetAudioDevice( _dev );
|
||||
|
||||
emit qualitySettingsChanged();
|
||||
emit sampleRateChanged();
|
||||
|
||||
@@ -574,13 +574,9 @@ NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrac
|
||||
int midiEventChannel,
|
||||
NotePlayHandle::Origin origin )
|
||||
{
|
||||
if( s_availableIndex < 0 )
|
||||
{
|
||||
s_mutex.lockForWrite();
|
||||
if( s_availableIndex < 0 ) extend( NPH_CACHE_INCREMENT );
|
||||
s_mutex.unlock();
|
||||
}
|
||||
s_mutex.lockForRead();
|
||||
// TODO: use some lockless data structures
|
||||
s_mutex.lockForWrite();
|
||||
if (s_availableIndex < 0) { extend(NPH_CACHE_INCREMENT); }
|
||||
NotePlayHandle * nph = s_available[s_availableIndex--];
|
||||
s_mutex.unlock();
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "JournallingObject.h"
|
||||
#include "Song.h"
|
||||
|
||||
//! Avoid clashes between loaded IDs (have the bit cleared)
|
||||
//! and newly created IDs (have the bit set)
|
||||
static const int EO_ID_MSB = 1 << 23;
|
||||
|
||||
const int ProjectJournal::MAX_UNDO_STATES = 100; // TODO: make this configurable in settings
|
||||
|
||||
@@ -73,7 +73,7 @@ SampleBuffer::SampleBuffer() :
|
||||
m_amplification( 1.0f ),
|
||||
m_reversed( false ),
|
||||
m_frequency( BaseFreq ),
|
||||
m_sampleRate( Engine::mixer()->baseSampleRate() )
|
||||
m_sampleRate( mixerSampleRate () )
|
||||
{
|
||||
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
|
||||
@@ -143,6 +143,11 @@ void SampleBuffer::sampleRateChanged()
|
||||
update( true );
|
||||
}
|
||||
|
||||
sample_rate_t SampleBuffer::mixerSampleRate()
|
||||
{
|
||||
return Engine::mixer()->processingSampleRate();
|
||||
}
|
||||
|
||||
|
||||
void SampleBuffer::update( bool _keep_settings )
|
||||
{
|
||||
@@ -178,7 +183,7 @@ void SampleBuffer::update( bool _keep_settings )
|
||||
int_sample_t * buf = NULL;
|
||||
sample_t * fbuf = NULL;
|
||||
ch_cnt_t channels = DEFAULT_CHANNELS;
|
||||
sample_rate_t samplerate = Engine::mixer()->baseSampleRate();
|
||||
sample_rate_t samplerate = mixerSampleRate();
|
||||
m_frames = 0;
|
||||
|
||||
const QFileInfo fileInfo( file );
|
||||
@@ -366,10 +371,10 @@ void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr,
|
||||
bool _keep_settings )
|
||||
{
|
||||
// do samplerate-conversion to our default-samplerate
|
||||
if( _src_sr != Engine::mixer()->baseSampleRate() )
|
||||
if( _src_sr != mixerSampleRate() )
|
||||
{
|
||||
SampleBuffer * resampled = resample( _src_sr,
|
||||
Engine::mixer()->baseSampleRate() );
|
||||
mixerSampleRate() );
|
||||
MM_FREE( m_data );
|
||||
m_frames = resampled->frames();
|
||||
m_data = MM_ALLOC( sampleFrame, m_frames );
|
||||
|
||||
@@ -141,7 +141,7 @@ bool SamplePlayHandle::isFromTrack( const Track * _track ) const
|
||||
|
||||
f_cnt_t SamplePlayHandle::totalFrames() const
|
||||
{
|
||||
return ( m_sampleBuffer->endFrame() - m_sampleBuffer->startFrame() ) * ( Engine::mixer()->processingSampleRate() / Engine::mixer()->baseSampleRate() );
|
||||
return ( m_sampleBuffer->endFrame() - m_sampleBuffer->startFrame() ) * ( Engine::mixer()->processingSampleRate() / m_sampleBuffer->sampleRate() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ bool AudioFileMP3::initEncoder()
|
||||
lame_set_brate(m_lame, bitRate);
|
||||
|
||||
// Add a comment
|
||||
id3tag_init(m_lame);
|
||||
id3tag_set_comment(m_lame, "Created with LMMS");
|
||||
|
||||
return lame_init_params(m_lame) != -1;
|
||||
|
||||
@@ -84,6 +84,7 @@ TimeLineWidget::TimeLineWidget( const int xoff, const int yoff, const float ppt,
|
||||
|
||||
m_xOffset -= s_posMarkerPixmap->width() / 2;
|
||||
|
||||
setMouseTracking(true);
|
||||
m_pos.m_timeLine = this;
|
||||
|
||||
QTimer * updateTimer = new QTimer( this );
|
||||
@@ -351,6 +352,7 @@ void TimeLineWidget::mousePressEvent( QMouseEvent* event )
|
||||
|
||||
void TimeLineWidget::mouseMoveEvent( QMouseEvent* event )
|
||||
{
|
||||
parentWidget()->update(); // essential for widgets that this timeline had taken their mouse move event from.
|
||||
const MidiTime t = m_begin + static_cast<int>( qMax( event->x() - m_xOffset - m_moveXOff, 0 ) * MidiTime::ticksPerTact() / m_ppt );
|
||||
|
||||
switch( m_action )
|
||||
|
||||
@@ -431,8 +431,8 @@ void AutomationEditor::leaveEvent(QEvent * e )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
QWidget::leaveEvent( e );
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
@@ -1511,8 +1511,11 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
|
||||
case SELECT: cursor = s_toolSelect; break;
|
||||
case MOVE: cursor = s_toolMove; break;
|
||||
}
|
||||
p.drawPixmap( mapFromGlobal( QCursor::pos() ) + QPoint( 8, 8 ),
|
||||
*cursor );
|
||||
QPoint mousePosition = mapFromGlobal( QCursor::pos() );
|
||||
if( cursor != NULL && mousePosition.y() > TOP_MARGIN + SCROLLBAR_SIZE)
|
||||
{
|
||||
p.drawPixmap( mousePosition + QPoint( 8, 8 ), *cursor );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1435,6 +1435,7 @@ void PianoRoll::leaveEvent(QEvent * e )
|
||||
|
||||
QWidget::leaveEvent( e );
|
||||
s_textFloat->hide();
|
||||
update(); // cleaning inner mouse-related graphics
|
||||
}
|
||||
|
||||
|
||||
@@ -3433,10 +3434,10 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
case ModeSelect: cursor = s_toolSelect; break;
|
||||
case ModeEditDetuning: cursor = s_toolOpen; break;
|
||||
}
|
||||
if( cursor != NULL )
|
||||
QPoint mousePosition = mapFromGlobal( QCursor::pos() );
|
||||
if( cursor != NULL && mousePosition.y() > keyAreaTop() && mousePosition.x() > noteEditLeft())
|
||||
{
|
||||
p.drawPixmap( mapFromGlobal( QCursor::pos() ) + QPoint( 8, 8 ),
|
||||
*cursor );
|
||||
p.drawPixmap( mousePosition + QPoint( 8, 8 ), *cursor );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,9 @@ SampleTCO::~SampleTCO()
|
||||
{
|
||||
sampletrack->updateTcos();
|
||||
}
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
sharedObject::unref( m_sampleBuffer );
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +139,9 @@ const QString & SampleTCO::sampleFile() const
|
||||
|
||||
void SampleTCO::setSampleBuffer( SampleBuffer* sb )
|
||||
{
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
sharedObject::unref( m_sampleBuffer );
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
m_sampleBuffer = sb;
|
||||
updateLength();
|
||||
|
||||
@@ -269,6 +273,8 @@ void SampleTCO::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
QString s;
|
||||
_this.setAttribute( "data", m_sampleBuffer->toBase64( s ) );
|
||||
}
|
||||
|
||||
_this.setAttribute ("sample_rate", m_sampleBuffer->sampleRate());
|
||||
// TODO: start- and end-frame
|
||||
}
|
||||
|
||||
@@ -289,6 +295,10 @@ void SampleTCO::loadSettings( const QDomElement & _this )
|
||||
changeLength( _this.attribute( "len" ).toInt() );
|
||||
setMuted( _this.attribute( "muted" ).toInt() );
|
||||
setStartTimeOffset( _this.attribute( "off" ).toInt() );
|
||||
|
||||
if (_this.hasAttribute("sample_rate")) {
|
||||
m_sampleBuffer->setSampleRate(_this.attribute("sample_rate").toInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -628,13 +638,14 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames,
|
||||
{
|
||||
TrackContentObject * tco = getTCO( i );
|
||||
SampleTCO * sTco = dynamic_cast<SampleTCO*>( tco );
|
||||
float framesPerTick = Engine::framesPerTick();
|
||||
|
||||
if( _start >= sTco->startPosition() && _start < sTco->endPosition() )
|
||||
{
|
||||
if( sTco->isPlaying() == false && _start > sTco->startPosition() + sTco->startTimeOffset() )
|
||||
{
|
||||
f_cnt_t sampleStart = framesPerTick * ( _start - sTco->startPosition() - sTco->startTimeOffset() );
|
||||
f_cnt_t tcoFrameLength = framesPerTick * ( sTco->endPosition() - sTco->startPosition() - sTco->startTimeOffset() );
|
||||
auto bufferFramesPerTick = Engine::framesPerTick (sTco->sampleBuffer ()->sampleRate ());
|
||||
f_cnt_t sampleStart = bufferFramesPerTick * ( _start - sTco->startPosition() - sTco->startTimeOffset() );
|
||||
f_cnt_t tcoFrameLength = bufferFramesPerTick * ( sTco->endPosition() - sTco->startPosition() - sTco->startTimeOffset() );
|
||||
f_cnt_t sampleBufferLength = sTco->sampleBuffer()->frames();
|
||||
//if the Tco smaller than the sample length we play only until Tco end
|
||||
//else we play the sample to the end but nothing more
|
||||
|
||||
Reference in New Issue
Block a user