diff --git a/include/AudioDevice.h b/include/AudioDevice.h index 35f5ec6207f..c9ad7f4b3cd 100644 --- a/include/AudioDevice.h +++ b/include/AudioDevice.h @@ -115,7 +115,7 @@ class AudioDevice const fpp_t _frames ); // resample given buffer from samplerate _src_sr to samplerate _dst_sr - void resample( const surroundSampleFrame * _src, + fpp_t resample( const surroundSampleFrame * _src, const fpp_t _frames, surroundSampleFrame * _dst, const sample_rate_t _src_sr, diff --git a/include/PianoRoll.h b/include/PianoRoll.h index bf8aa983c06..86a65050c1d 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -406,6 +406,9 @@ protected slots: volume_t m_lastNoteVolume; panning_t m_lastNotePanning; + //When resizing several notes, we want to calculate a common minimum length + MidiTime m_minResizeLen; + int m_startKey; // first key when drawing int m_lastKey; diff --git a/src/core/audio/AudioDevice.cpp b/src/core/audio/AudioDevice.cpp index ab69e144b12..f794602299b 100644 --- a/src/core/audio/AudioDevice.cpp +++ b/src/core/audio/AudioDevice.cpp @@ -93,10 +93,8 @@ fpp_t AudioDevice::getNextBuffer( surroundSampleFrame * _ab ) // resample if necessary if( mixer()->processingSampleRate() != m_sampleRate ) { - resample( b, frames, _ab, mixer()->processingSampleRate(), - m_sampleRate ); - frames = frames * m_sampleRate / - mixer()->processingSampleRate(); + frames = resample( b, frames, _ab, mixer()->processingSampleRate(), + m_sampleRate ); } else { @@ -184,7 +182,7 @@ void AudioDevice::renamePort( AudioPort * ) -void AudioDevice::resample( const surroundSampleFrame * _src, +fpp_t AudioDevice::resample( const surroundSampleFrame * _src, const fpp_t _frames, surroundSampleFrame * _dst, const sample_rate_t _src_sr, @@ -192,7 +190,7 @@ void AudioDevice::resample( const surroundSampleFrame * _src, { if( m_srcState == NULL ) { - return; + return _frames; } m_srcData.input_frames = _frames; m_srcData.output_frames = _frames; @@ -206,6 +204,7 @@ void AudioDevice::resample( const surroundSampleFrame * _src, printf( "AudioDevice::resample(): error while resampling: %s\n", src_strerror( error ) ); } + return static_cast(m_srcData.output_frames_gen); } diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp index 782aafcd6ed..fae1d5dad7b 100644 --- a/src/gui/FxMixerView.cpp +++ b/src/gui/FxMixerView.cpp @@ -412,12 +412,9 @@ void FxMixerView::deleteChannel(int index) m_channelAreaWidget->adjustSize(); // make sure every channel knows what index it is - for(int i=0; i index ) - { - m_fxChannelViews[i]->m_fxLine->setChannelIndex(i-1); - } + m_fxChannelViews[i]->m_fxLine->setChannelIndex(i-1); } m_fxChannelViews.remove(index); @@ -439,38 +436,32 @@ void FxMixerView::deleteUnusedChannels() tracks += Engine::getSong()->tracks(); tracks += Engine::getBBTrackContainer()->tracks(); - // go through all FX Channels - for(int i = m_fxChannelViews.size()-1; i > 0; --i) + std::vector inUse(m_fxChannelViews.size(), false); + + //Populate inUse by checking the destination channel for every track + for (Track* t: tracks) { - // check if an instrument references to the current channel - bool empty=true; - for( Track* t : tracks ) + //The channel that this track sends to. Since master channel is always in use, + //setting this to 0 is a safe default (for tracks that don't sent to the mixer). + int channel = 0; + if (t->type() == Track::InstrumentTrack) { - if( t->type() == Track::InstrumentTrack ) - { - InstrumentTrack* inst = dynamic_cast( t ); - if( i == inst->effectChannelModel()->value(0) ) - { - empty=false; - break; - } - } - else if( t->type() == Track::SampleTrack ) - { - SampleTrack *strack = dynamic_cast( t ); - if( i == strack->effectChannelModel()->value(0) ) - { - empty=false; - break; - } - } + InstrumentTrack* inst = dynamic_cast(t); + channel = inst->effectChannelModel()->value(); } - FxChannel * ch = Engine::fxMixer()->effectChannel( i ); - // delete channel if no references found - if( empty && ch->m_receives.isEmpty() ) + else if (t->type() == Track::SampleTrack) { - deleteChannel( i ); + SampleTrack *strack = dynamic_cast(t); + channel = strack->effectChannelModel()->value(); } + inUse[channel] = true; + } + + //Check all channels except master, delete those with no incoming sends + for(int i = m_fxChannelViews.size()-1; i > 0; --i) + { + if (!inUse[i] && Engine::fxMixer()->effectChannel(i)->m_receives.isEmpty()) + { deleteChannel(i); } } } diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index e0f4fdadff0..2f948523abc 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -181,6 +181,7 @@ PianoRoll::PianoRoll() : m_lenOfNewNotes( MidiTime( 0, DefaultTicksPerBar/4 ) ), m_lastNoteVolume( DefaultVolume ), m_lastNotePanning( DefaultPanning ), + m_minResizeLen( 0 ), m_startKey( INITIAL_START_KEY ), m_lastKey( 0 ), m_editMode( ModeDraw ), @@ -1727,9 +1728,21 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) // then resize the note m_action = ActionResizeNote; + //Calculate the minimum length we should allow when resizing + //each note, and let all notes use the smallest one found + m_minResizeLen = quantization(); for (Note *note : selectedNotes) { - if (note->oldLength() <= 0) { note->setOldLength(4); } + //Notes from the BB editor can have a negative length, so + //change their length to the displayed one before resizing + if (note->oldLength() <= 0) { note->setOldLength(4); } + //Let the note be sized down by quantized increments, stopping + //when the next step down would result in a negative length + int thisMin = note->oldLength() % quantization(); + //The initial value for m_minResizeLen is the minimum length of + //a note divisible by the current Q. Therefore we ignore notes + //where thisMin == 0 when checking for a new minimum + if (thisMin > 0 && thisMin < m_minResizeLen) { m_minResizeLen = thisMin; } } // set resize-cursor @@ -2664,7 +2677,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 - + auto selectedNotes = getSelectedNotes(); if (shift) @@ -2750,11 +2763,12 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) else { // shift is not pressed; stretch length of selected notes but not their position + int minLength = alt ? 1 : m_minResizeLen.getTicks(); + for (Note *note : selectedNotes) { - int newLength = note->oldLength() + off_ticks; - newLength = qMax(1, newLength); - note->setLength( MidiTime(newLength) ); + int newLength = qMax(minLength, note->oldLength() + off_ticks); + note->setLength(MidiTime(newLength)); m_lenOfNewNotes = note->length(); } diff --git a/src/gui/widgets/InstrumentMidiIOView.cpp b/src/gui/widgets/InstrumentMidiIOView.cpp index 62d1dbb1828..4cc28b15fe9 100644 --- a/src/gui/widgets/InstrumentMidiIOView.cpp +++ b/src/gui/widgets/InstrumentMidiIOView.cpp @@ -53,18 +53,22 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget* parent ) : QHBoxLayout* midiInputLayout = new QHBoxLayout( m_midiInputGroupBox ); midiInputLayout->setContentsMargins( 8, 18, 8, 8 ); - midiInputLayout->setSpacing( 6 ); + midiInputLayout->setSpacing( 4 ); m_inputChannelSpinBox = new LcdSpinBox( 2, m_midiInputGroupBox ); m_inputChannelSpinBox->addTextForValue( 0, "--" ); - m_inputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of two digits */ + m_inputChannelSpinBox->setLabel( tr( "CHAN" ) ); m_inputChannelSpinBox->setEnabled( false ); midiInputLayout->addWidget( m_inputChannelSpinBox ); m_fixedInputVelocitySpinBox = new LcdSpinBox( 3, m_midiInputGroupBox ); m_fixedInputVelocitySpinBox->setDisplayOffset( 1 ); m_fixedInputVelocitySpinBox->addTextForValue( 0, "---" ); - m_fixedInputVelocitySpinBox->setLabel( tr( "VELOCITY" ) ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of three digits */ + m_fixedInputVelocitySpinBox->setLabel( tr( "VELOC" ) ); m_fixedInputVelocitySpinBox->setEnabled( false ); midiInputLayout->addWidget( m_fixedInputVelocitySpinBox ); midiInputLayout->addStretch(); @@ -81,28 +85,37 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget* parent ) : QHBoxLayout* midiOutputLayout = new QHBoxLayout( m_midiOutputGroupBox ); midiOutputLayout->setContentsMargins( 8, 18, 8, 8 ); - midiOutputLayout->setSpacing( 6 ); + midiOutputLayout->setSpacing( 4 ); m_outputChannelSpinBox = new LcdSpinBox( 2, m_midiOutputGroupBox ); m_outputChannelSpinBox->addTextForValue( 0, "--" ); - m_outputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of two digits */ + m_outputChannelSpinBox->setLabel( tr( "CHAN" ) ); + m_outputChannelSpinBox->setEnabled( false ); midiOutputLayout->addWidget( m_outputChannelSpinBox ); m_fixedOutputVelocitySpinBox = new LcdSpinBox( 3, m_midiOutputGroupBox ); m_fixedOutputVelocitySpinBox->setDisplayOffset( 1 ); m_fixedOutputVelocitySpinBox->addTextForValue( 0, "---" ); - m_fixedOutputVelocitySpinBox->setLabel( tr( "VELOCITY" ) ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of three digits */ + m_fixedOutputVelocitySpinBox->setLabel( tr( "VELOC" ) ); m_fixedOutputVelocitySpinBox->setEnabled( false ); midiOutputLayout->addWidget( m_fixedOutputVelocitySpinBox ); m_outputProgramSpinBox = new LcdSpinBox( 3, m_midiOutputGroupBox ); - m_outputProgramSpinBox->setLabel( tr( "PROGRAM" ) ); + /*: This string must be be short, its width must be less than the + * width of LCD spin-box of three digits */ + m_outputProgramSpinBox->setLabel( tr( "PROG" ) ); m_outputProgramSpinBox->setEnabled( false ); midiOutputLayout->addWidget( m_outputProgramSpinBox ); m_fixedOutputNoteSpinBox = new LcdSpinBox( 3, m_midiOutputGroupBox ); m_fixedOutputNoteSpinBox->setDisplayOffset( 1 ); m_fixedOutputNoteSpinBox->addTextForValue( 0, "---" ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of three digits */ m_fixedOutputNoteSpinBox->setLabel( tr( "NOTE" ) ); m_fixedOutputNoteSpinBox->setEnabled( false ); midiOutputLayout->addWidget( m_fixedOutputNoteSpinBox ); @@ -211,6 +224,7 @@ InstrumentMiscView::InstrumentMiscView(InstrumentTrack *it, QWidget *parent) : QHBoxLayout* masterPitchLayout = new QHBoxLayout( m_pitchGroupBox ); masterPitchLayout->setContentsMargins( 8, 18, 8, 8 ); QLabel *tlabel = new QLabel(tr( "Enables the use of master pitch" ) ); + tlabel->setFont( pointSize<8>( tlabel->font() ) ); m_pitchGroupBox->setModel( &it->m_useMasterPitchModel ); masterPitchLayout->addWidget( tlabel ); layout->addStretch();