diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index 3fbb2e6fb..cf609066a 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -622,6 +622,8 @@ TrackContentObjectView { qproperty-textBackgroundColor: rgba(0, 0, 0, 75); qproperty-textShadowColor: rgb( 0, 0, 0 ); qproperty-gradient: true; /* boolean property, set true to have a gradient */ + /* finger tip offset of cursor */ + qproperty-mouseHotspotHand: 3px 3px; font-size: 11px; } diff --git a/data/themes/default/style.css b/data/themes/default/style.css index bedb8ea32..feb85a612 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -660,6 +660,8 @@ TrackContentObjectView { qproperty-textBackgroundColor: rgba(0, 0, 0, 75); qproperty-textShadowColor: rgba(0,0,0,200); qproperty-gradient: false; /* boolean property, set true to have a gradient */ + /* finger tip offset of cursor */ + qproperty-mouseHotspotHand: 7px 2px; font-size: 11px; } diff --git a/include/AudioJack.h b/include/AudioJack.h index c3207c829..a80e88552 100644 --- a/include/AudioJack.h +++ b/include/AudioJack.h @@ -34,6 +34,7 @@ #include "weak_libjack.h" #endif +#include #include #include #include @@ -57,6 +58,7 @@ public: // the jack callback is handled here, we call the midi client so that it can read // it's midi data during the callback AudioJack * addMidiClient(MidiJack *midiClient); + void removeMidiClient(void) { m_midiClient = nullptr; } jack_client_t * jackClient() {return m_client;}; inline static QString name() @@ -106,9 +108,9 @@ private: jack_client_t * m_client; bool m_active; - bool m_stopped; + std::atomic m_stopped; - MidiJack *m_midiClient; + std::atomic m_midiClient; QVector m_outputPorts; jack_default_audio_sample_t * * m_tempOutBufs; surroundSampleFrame * m_outBuf; diff --git a/include/Knob.h b/include/Knob.h index 0bba58afd..b129bc8d6 100644 --- a/include/Knob.h +++ b/include/Knob.h @@ -173,8 +173,7 @@ private: BoolModel m_volumeKnob; FloatModel m_volumeRatio; - QPoint m_mouseOffset; - QPoint m_origMousePos; + QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent float m_leftOver; bool m_buttonPressed; diff --git a/include/LcdSpinBox.h b/include/LcdSpinBox.h index 379b743ac..91ac8b4a7 100644 --- a/include/LcdSpinBox.h +++ b/include/LcdSpinBox.h @@ -73,8 +73,9 @@ protected: void mouseDoubleClickEvent( QMouseEvent * _me ) override; private: + float m_remainder; //!< floating offset of spinbox in [-0.5, 0.5] bool m_mouseMoving; - QPoint m_origMousePos; + QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent int m_displayOffset; void enterValue(); diff --git a/include/Track.h b/include/Track.h index 07cee8ffd..89c95059c 100644 --- a/include/Track.h +++ b/include/Track.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -206,6 +207,9 @@ class TrackContentObjectView : public selectableObject, public ModelView Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor ) Q_PROPERTY( QColor BBPatternBackground READ BBPatternBackground WRITE setBBPatternBackground ) Q_PROPERTY( bool gradient READ gradient WRITE setGradient ) + // We have to use a QSize here because using QPoint isn't supported. + // width -> x, height -> y + Q_PROPERTY( QSize mouseHotspotHand WRITE setMouseHotspotHand ) public: TrackContentObjectView( TrackContentObject * tco, TrackView * tv ); @@ -240,6 +244,7 @@ public: void setTextShadowColor( const QColor & c ); void setBBPatternBackground( const QColor & c ); void setGradient( const bool & b ); + void setMouseHotspotHand(const QSize & s); // access needsUpdate member variable bool needsUpdate(); @@ -316,8 +321,10 @@ private: QColor m_textShadowColor; QColor m_BBPatternBackground; bool m_gradient; + QSize m_mouseHotspotHand; // QSize must be used because QPoint isn't supported by property system + bool m_cursorSetYet; - bool m_needsUpdate; + bool m_needsUpdate; inline void setInitialPos( QPoint pos ) { m_initialMousePos = pos; diff --git a/plugins/Eq/EqSpectrumView.h b/plugins/Eq/EqSpectrumView.h index cd3f17758..84feeff13 100644 --- a/plugins/Eq/EqSpectrumView.h +++ b/plugins/Eq/EqSpectrumView.h @@ -24,6 +24,7 @@ #define EQSPECTRUMVIEW_H #include +#include #include #include "fft_helpers.h" diff --git a/plugins/sf2_player/sf2_player.cpp b/plugins/sf2_player/sf2_player.cpp index 99af22781..2f9456370 100644 --- a/plugins/sf2_player/sf2_player.cpp +++ b/plugins/sf2_player/sf2_player.cpp @@ -396,18 +396,24 @@ void sf2Instrument::openFile( const QString & _sf2File, bool updateTrackName ) // Add to map, if doesn't exist. else { - m_fontId = fluid_synth_sfload( m_synth, sf2Ascii, true ); + bool loaded = false; + if( fluid_is_soundfont( sf2Ascii ) ) + { + m_fontId = fluid_synth_sfload( m_synth, sf2Ascii, true ); - if( fluid_synth_sfcount( m_synth ) > 0 ) - { - // Grab this sf from the top of the stack and add to list - m_font = new sf2Font( fluid_synth_get_sfont( m_synth, 0 ) ); - s_fonts.insert( relativePath, m_font ); + if( fluid_synth_sfcount( m_synth ) > 0 ) + { + // Grab this sf from the top of the stack and add to list + m_font = new sf2Font( fluid_synth_get_sfont( m_synth, 0 ) ); + s_fonts.insert( relativePath, m_font ); + loaded = true; + } } - else + + if(!loaded) { - collectErrorForUI( sf2Instrument::tr( "A soundfont %1 could not be loaded." ).arg( QFileInfo( _sf2File ).baseName() ) ); - // TODO: Why is the filename missing when the file does not exist? + collectErrorForUI( sf2Instrument::tr( "A soundfont %1 could not be loaded." ). + arg( QFileInfo( _sf2File ).baseName() ) ); } } diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index 3f22a22e1..476d54fef 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -1207,8 +1207,18 @@ MidiClient * Mixer::tryMidiClients() printf( "midi apple didn't work: client_name=%s\n", client_name.toUtf8().constData()); #endif - printf( "Couldn't create MIDI-client, neither with ALSA nor with " - "OSS. Will use dummy-MIDI-client.\n" ); + if(client_name != MidiDummy::name()) + { + if (client_name.isEmpty()) + { + printf("Unknown MIDI-client. "); + } + else + { + printf("Couldn't create %s MIDI-client. ", client_name.toUtf8().constData()); + } + printf("Will use dummy-MIDI-client.\n"); + } m_midiClientName = MidiDummy::name(); diff --git a/src/core/Track.cpp b/src/core/Track.cpp index f6b109280..15625d87c 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -282,6 +282,8 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, m_textShadowColor( 0, 0, 0 ), m_BBPatternBackground( 0, 0, 0 ), m_gradient( true ), + m_mouseHotspotHand( 0, 0 ), + m_cursorSetYet( false ), m_needsUpdate( true ) { if( s_textFloat == NULL ) @@ -293,7 +295,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, setAttribute( Qt::WA_OpaquePaintEvent, true ); setAttribute( Qt::WA_DeleteOnClose, true ); setFocusPolicy( Qt::StrongFocus ); - setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) ); + setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) ); move( 0, 0 ); show(); @@ -342,6 +344,12 @@ TrackContentObjectView::~TrackContentObjectView() */ void TrackContentObjectView::update() { + if( !m_cursorSetYet ) + { + setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) ); + m_cursorSetYet = true; + } + if( fixedTCOs() ) { updateLength(); @@ -422,6 +430,11 @@ void TrackContentObjectView::setBBPatternBackground( const QColor & c ) void TrackContentObjectView::setGradient( const bool & b ) { m_gradient = b; } +void TrackContentObjectView::setMouseHotspotHand(const QSize & s) +{ + m_mouseHotspotHand = s; +} + // access needsUpdate member variable bool TrackContentObjectView::needsUpdate() { return m_needsUpdate; } @@ -609,7 +622,7 @@ void TrackContentObjectView::leaveEvent( QEvent * e ) { if( cursor().shape() != Qt::BitmapCursor ) { - setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) ); + setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) ); } if( e != NULL ) { diff --git a/src/core/audio/AudioJack.cpp b/src/core/audio/AudioJack.cpp index aebfe5e1c..44ecafa23 100644 --- a/src/core/audio/AudioJack.cpp +++ b/src/core/audio/AudioJack.cpp @@ -55,6 +55,8 @@ AudioJack::AudioJack( bool & _success_ful, Mixer* _mixer ) : m_framesDoneInCurBuf( 0 ), m_framesToDoInCurBuf( 0 ) { + m_stopped = true; + _success_ful = initJackClient(); if( _success_ful ) { @@ -200,8 +202,6 @@ bool AudioJack::initJackClient() void AudioJack::startProcessing() { - m_stopped = false; - if( m_active || m_client == NULL ) { return; @@ -244,6 +244,7 @@ void AudioJack::startProcessing() } } + m_stopped = false; free( ports ); } @@ -344,8 +345,8 @@ int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata ) // add to the following sound processing if( m_midiClient && _nframes > 0 ) { - m_midiClient->JackMidiRead(_nframes); - m_midiClient->JackMidiWrite(_nframes); + m_midiClient.load()->JackMidiRead(_nframes); + m_midiClient.load()->JackMidiWrite(_nframes); } for( int c = 0; c < channels(); ++c ) diff --git a/src/core/midi/MidiJack.cpp b/src/core/midi/MidiJack.cpp index 568b6dae1..bd1e65111 100644 --- a/src/core/midi/MidiJack.cpp +++ b/src/core/midi/MidiJack.cpp @@ -95,6 +95,8 @@ MidiJack::MidiJack() : /* jack midi out not implemented JackMidiWrite and sendByte needs to be functional before enabling this + If you enable this, also enable the + corresponding jack_port_unregister line below m_output_port = jack_port_register( jackClient(), "MIDI out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); @@ -116,13 +118,18 @@ MidiJack::~MidiJack() { if(jackClient()) { + // remove ourselves first (atomically), so we will not get called again + m_jackAudio->removeMidiClient(); + if( jack_port_unregister( jackClient(), m_input_port) != 0){ printf("Failed to unregister jack midi input\n"); } + /* Unused yet, see the corresponding jack_port_register call if( jack_port_unregister( jackClient(), m_output_port) != 0){ printf("Failed to unregister jack midi output\n"); } + */ if(m_jackClient) { @@ -174,19 +181,22 @@ void MidiJack::JackMidiRead(jack_nframes_t nframes) jack_nframes_t event_index = 0; jack_nframes_t event_count = jack_midi_get_event_count(port_buf); - jack_midi_event_get(&in_event, port_buf, 0); - for(i=0; i #include +#include #include #include "AutomationEditor.h" diff --git a/src/gui/LmmsStyle.cpp b/src/gui/LmmsStyle.cpp index b6a139bbb..1f6d6f1cd 100644 --- a/src/gui/LmmsStyle.cpp +++ b/src/gui/LmmsStyle.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index 048123ef5..265977ad5 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 4682b3f20..d4e29ad41 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -1772,6 +1772,11 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) // then resize the note m_action = ActionResizeNote; + for (Note *note : getSelectedNotes()) + { + if (note->oldLength() <= 0) { note->setOldLength(4); } + } + // set resize-cursor setCursor( Qt::SizeHorCursor ); } diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 2546582f6..920c9765d 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -496,8 +496,8 @@ float Knob::getValue( const QPoint & _p ) { float value; - // arcane mathemagicks for calculating knob movement - value = ( ( _p.y() + _p.y() * qMin( qAbs( _p.y() / 2.5f ), 6.0f ) ) ) / 12.0f; + // knob value increase is linear to mouse movement + value = .4f * _p.y(); // if shift pressed we want slower movement if( gui->mainWindow()->isShiftPressed() ) @@ -585,13 +585,11 @@ void Knob::mousePressEvent( QMouseEvent * _me ) } const QPoint & p = _me->pos(); - m_origMousePos = p; - m_mouseOffset = QPoint(0, 0); + m_lastMousePos = p; m_leftOver = 0.0f; emit sliderPressed(); - QApplication::setOverrideCursor( Qt::BlankCursor ); s_textFloat->setText( displayValue() ); s_textFloat->moveGlobal( this, QPoint( width() + 2, 0 ) ); @@ -616,12 +614,13 @@ void Knob::mousePressEvent( QMouseEvent * _me ) void Knob::mouseMoveEvent( QMouseEvent * _me ) { - if( m_buttonPressed && _me->pos() != m_origMousePos ) + if( m_buttonPressed && _me->pos() != m_lastMousePos ) { - m_mouseOffset = _me->pos() - m_origMousePos; - setPosition( m_mouseOffset ); + // knob position is changed depending on last mouse position + setPosition( _me->pos() - m_lastMousePos ); emit sliderMoved( model()->value() ); - QCursor::setPos( mapToGlobal( m_origMousePos ) ); + // original position for next time is current position + m_lastMousePos = _me->pos(); } s_textFloat->setText( displayValue() ); } diff --git a/src/gui/widgets/LcdSpinBox.cpp b/src/gui/widgets/LcdSpinBox.cpp index 8b30a38ca..6cbdc8103 100644 --- a/src/gui/widgets/LcdSpinBox.cpp +++ b/src/gui/widgets/LcdSpinBox.cpp @@ -23,6 +23,7 @@ * */ +#include #include #include #include @@ -40,8 +41,9 @@ LcdSpinBox::LcdSpinBox( int numDigits, QWidget* parent, const QString& name ) : LcdWidget( numDigits, parent, name ), IntModelView( new IntModel( 0, 0, 0, NULL, name, true ), this ), + m_remainder( 0.f ), m_mouseMoving( false ), - m_origMousePos(), + m_lastMousePos(), m_displayOffset( 0 ) { } @@ -52,8 +54,9 @@ LcdSpinBox::LcdSpinBox( int numDigits, QWidget* parent, const QString& name ) : LcdSpinBox::LcdSpinBox( int numDigits, const QString& style, QWidget* parent, const QString& name ) : LcdWidget( numDigits, parent, name ), IntModelView( new IntModel( 0, 0, 0, NULL, name, true ), this ), + m_remainder( 0.f ), m_mouseMoving( false ), - m_origMousePos(), + m_lastMousePos(), m_displayOffset( 0 ) { } @@ -90,8 +93,7 @@ void LcdSpinBox::mousePressEvent( QMouseEvent* event ) event->y() < cellHeight() + 2 ) { m_mouseMoving = true; - m_origMousePos = event->globalPos(); - QApplication::setOverrideCursor( Qt::BlankCursor ); + m_lastMousePos = event->globalPos(); AutomatableModel *thisModel = model(); if( thisModel ) @@ -113,15 +115,20 @@ void LcdSpinBox::mouseMoveEvent( QMouseEvent* event ) { if( m_mouseMoving ) { - int dy = event->globalY() - m_origMousePos.y(); - if( event->modifiers() & Qt::ShiftModifier ) - dy = qBound( -4, dy/4, 4 ); - if( dy > 1 || dy < -1 ) + int dy = event->globalY() - m_lastMousePos.y(); + if( dy ) { - model()->setInitValue( model()->value() - - dy / 2 * model()->step() ); + float fdy = static_cast(dy); + if( event->modifiers() & Qt::ShiftModifier ) { + fdy = qBound( -4.f, fdy/4.f, 4.f ); + } + float floatValNotRounded = + model()->value() + m_remainder - fdy / 2.f * model()->step(); + float floatValRounded = roundf( floatValNotRounded ); + m_remainder = floatValNotRounded - floatValRounded; + model()->setInitValue( floatValRounded ); emit manualChange(); - QCursor::setPos( m_origMousePos ); + m_lastMousePos = event->globalPos(); } } } @@ -134,10 +141,7 @@ void LcdSpinBox::mouseReleaseEvent( QMouseEvent* ) if( m_mouseMoving ) { model()->restoreJournallingState(); - - QCursor::setPos( m_origMousePos ); QApplication::restoreOverrideCursor(); - m_mouseMoving = false; } } @@ -179,5 +183,3 @@ void LcdSpinBox::enterValue() } } - -