mirror of
https://github.com/LMMS/lmms.git
synced 2026-03-04 22:26:07 -05:00
* Fixes createTCO method on some classes Classes that inherit from "Track", also inherit the createTCO method. That method takes a MidiTime position as an argument, but except on the class SampleTrack that argument was ignored. That lead to unnecessary calls to TCO->movePosition after creating a TCO in many parts of the codebase (making the argument completely redundant) and even to a bug on the BBEditor, caused by a call to createTCO that expected the position to be set on the constructor (see issue #5673). That PR adds code to move the TCO to the appropriate position inside the constructor of the classes that didn't have it, fixes the code style on the SampleTrack createTCO method and removes the now unneeded calls to movePosition from source files on src/ and plugins/. On Track::loadSettings there was a call to saveJournallingState(false) followed immediately by restoreJournallingState() which was deleted because it's redundant (probably a left over from copying the code from pasteSelection?). * Fix code style issues Fixes code style issues on some files (except for ones where the current statements already had a different code style. In those the used code style was kept for consistency). * Fixes more code style issues * Fixes code style issues on the parameter name Fixes code style issue on the parameter name of createTCO, where _pos was supposed to be just pos. The existing code had the old style and I ended up replicating it on the other methods. * Code style fixes Fixes code style in the changed lines. * Fixes bug with dragging to negative positions There was a bug (already present before this PR) where dragging a selection before MidiTime 0 would result in some TCOs being placed on negative positions. This PR fixes this bug by applying the following changes: 1) TrackContentObject::movePosition now moves the TCO to positions equal or above 0 only. 2) Because of the previous change, I removed the line that calculated the max value between 0 and the new position on TrackContentObjectView::mouseMoveEvent when dragging a single TCO (and added a line updating the value to the real new position of the TCO so the label displays the position correctly). 3) Unrelated to this bug, but removed an unnecessary call to TrackContentWidget::changePosition on the left resize of sample TCOs because it will already be called when movePosition triggers the positionChanged signal. 4) Added some logic to the TrackContentWidget::pasteSelection method to find the left most TCO being pasted and make sure that the offset is corrected so it doesn't end up on a negative position (similar to the logic for the MoveSelection action). 5) Removed another line that calculated the max between 0 and the new position on Track::removeBar since it's now safe to call movePosition with negative values. * Uses std::max instead of a conditional statement As suggested by Spekular, we use std::max instead of a conditional statement to correct the value of offset if it positions a TCO on a negative position.
491 lines
11 KiB
C++
491 lines
11 KiB
C++
/*
|
|
* InstrumentTrack.h - declaration of class InstrumentTrack, a track + window
|
|
* which holds an instrument-plugin
|
|
*
|
|
* Copyright (c) 2004-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
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#ifndef INSTRUMENT_TRACK_H
|
|
#define INSTRUMENT_TRACK_H
|
|
|
|
#include "AudioPort.h"
|
|
#include "GroupBox.h"
|
|
#include "InstrumentFunctions.h"
|
|
#include "InstrumentSoundShaping.h"
|
|
#include "MidiEventProcessor.h"
|
|
#include "MidiPort.h"
|
|
#include "NotePlayHandle.h"
|
|
#include "Piano.h"
|
|
#include "PianoView.h"
|
|
#include "Pitch.h"
|
|
#include "Plugin.h"
|
|
#include "Track.h"
|
|
|
|
|
|
|
|
class QLineEdit;
|
|
template<class T> class QQueue;
|
|
class InstrumentFunctionArpeggioView;
|
|
class InstrumentFunctionNoteStackingView;
|
|
class EffectRackView;
|
|
class InstrumentSoundShapingView;
|
|
class FadeButton;
|
|
class Instrument;
|
|
class InstrumentTrackWindow;
|
|
class InstrumentMidiIOView;
|
|
class InstrumentMiscView;
|
|
class Knob;
|
|
class FxLineLcdSpinBox;
|
|
class LcdSpinBox;
|
|
class LeftRightNav;
|
|
class midiPortMenu;
|
|
class DataFile;
|
|
class PluginView;
|
|
class TabWidget;
|
|
class TrackLabelButton;
|
|
class LedCheckBox;
|
|
class QLabel;
|
|
|
|
|
|
class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor
|
|
{
|
|
Q_OBJECT
|
|
MM_OPERATORS
|
|
mapPropertyFromModel(int,getVolume,setVolume,m_volumeModel);
|
|
public:
|
|
InstrumentTrack( TrackContainer* tc );
|
|
virtual ~InstrumentTrack();
|
|
|
|
// used by instrument
|
|
void processAudioBuffer( sampleFrame * _buf, const fpp_t _frames,
|
|
NotePlayHandle * _n );
|
|
|
|
MidiEvent applyMasterKey( const MidiEvent& event );
|
|
|
|
void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) override;
|
|
void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) override;
|
|
// silence all running notes played by this track
|
|
void silenceAllNotes( bool removeIPH = false );
|
|
|
|
bool isSustainPedalPressed() const
|
|
{
|
|
return m_sustainPedalPressed;
|
|
}
|
|
|
|
f_cnt_t beatLen( NotePlayHandle * _n ) const;
|
|
|
|
|
|
// for capturing note-play-events -> need that for arpeggio,
|
|
// filter and so on
|
|
void playNote( NotePlayHandle * _n, sampleFrame * _working_buffer );
|
|
|
|
QString instrumentName() const;
|
|
const Instrument *instrument() const
|
|
{
|
|
return m_instrument;
|
|
}
|
|
|
|
Instrument *instrument()
|
|
{
|
|
return m_instrument;
|
|
}
|
|
|
|
void deleteNotePluginData( NotePlayHandle * _n );
|
|
|
|
// name-stuff
|
|
void setName( const QString & _new_name ) override;
|
|
|
|
// translate given key of a note-event to absolute key (i.e.
|
|
// add global master-pitch and base-note of this instrument track)
|
|
int masterKey( int _midi_key ) const;
|
|
|
|
// translate pitch to midi-pitch [0,16383]
|
|
int midiPitch() const
|
|
{
|
|
return static_cast<int>( ( ( m_pitchModel.value() + m_pitchModel.range()/2 ) * MidiMaxPitchBend ) / m_pitchModel.range() );
|
|
}
|
|
|
|
/*! \brief Returns current range for pitch bend in semitones */
|
|
int midiPitchRange() const
|
|
{
|
|
return m_pitchRangeModel.value();
|
|
}
|
|
|
|
// play everything in given frame-range - creates note-play-handles
|
|
virtual bool play( const MidiTime & _start, const fpp_t _frames,
|
|
const f_cnt_t _frame_base, int _tco_num = -1 ) override;
|
|
// create new view for me
|
|
TrackView * createView( TrackContainerView* tcv ) override;
|
|
|
|
// create new track-content-object = pattern
|
|
TrackContentObject* createTCO(const MidiTime & pos) override;
|
|
|
|
|
|
// called by track
|
|
virtual void saveTrackSpecificSettings( QDomDocument & _doc,
|
|
QDomElement & _parent ) override;
|
|
void loadTrackSpecificSettings( const QDomElement & _this ) override;
|
|
|
|
using Track::setJournalling;
|
|
|
|
|
|
// load instrument whose name matches given one
|
|
Instrument * loadInstrument(const QString & _instrument_name,
|
|
const Plugin::Descriptor::SubPluginFeatures::Key* key = nullptr,
|
|
bool keyFromDnd = false);
|
|
|
|
AudioPort * audioPort()
|
|
{
|
|
return &m_audioPort;
|
|
}
|
|
|
|
MidiPort * midiPort()
|
|
{
|
|
return &m_midiPort;
|
|
}
|
|
|
|
const IntModel *baseNoteModel() const
|
|
{
|
|
return &m_baseNoteModel;
|
|
}
|
|
|
|
IntModel *baseNoteModel()
|
|
{
|
|
return &m_baseNoteModel;
|
|
}
|
|
|
|
int baseNote() const;
|
|
|
|
Piano *pianoModel()
|
|
{
|
|
return &m_piano;
|
|
}
|
|
|
|
bool isArpeggioEnabled() const
|
|
{
|
|
return m_arpeggio.m_arpEnabledModel.value();
|
|
}
|
|
|
|
// simple helper for removing midiport-XML-node when loading presets
|
|
static void removeMidiPortNode( DataFile& dataFile );
|
|
|
|
FloatModel * pitchModel()
|
|
{
|
|
return &m_pitchModel;
|
|
}
|
|
|
|
FloatModel * volumeModel()
|
|
{
|
|
return &m_volumeModel;
|
|
}
|
|
|
|
FloatModel * panningModel()
|
|
{
|
|
return &m_panningModel;
|
|
}
|
|
|
|
IntModel* pitchRangeModel()
|
|
{
|
|
return &m_pitchRangeModel;
|
|
}
|
|
|
|
IntModel * effectChannelModel()
|
|
{
|
|
return &m_effectChannelModel;
|
|
}
|
|
|
|
void setPreviewMode( const bool );
|
|
|
|
bool isPreviewMode() const
|
|
{
|
|
return m_previewMode;
|
|
}
|
|
|
|
void autoAssignMidiDevice( bool );
|
|
|
|
signals:
|
|
void instrumentChanged();
|
|
void midiNoteOn( const Note& );
|
|
void midiNoteOff( const Note& );
|
|
void nameChanged();
|
|
void newNote();
|
|
void endNote();
|
|
|
|
|
|
protected:
|
|
QString nodeName() const override
|
|
{
|
|
return "instrumenttrack";
|
|
}
|
|
|
|
// get the name of the instrument in the saved data
|
|
QString getSavedInstrumentName(const QDomElement & thisElement) const;
|
|
|
|
|
|
protected slots:
|
|
void updateBaseNote();
|
|
void updatePitch();
|
|
void updatePitchRange();
|
|
void updateEffectChannel();
|
|
|
|
|
|
private:
|
|
MidiPort m_midiPort;
|
|
|
|
NotePlayHandle* m_notes[NumKeys];
|
|
NotePlayHandleList m_sustainedNotes;
|
|
|
|
int m_runningMidiNotes[NumKeys];
|
|
QMutex m_midiNotesMutex;
|
|
|
|
bool m_sustainPedalPressed;
|
|
|
|
bool m_silentBuffersProcessed;
|
|
|
|
bool m_previewMode;
|
|
|
|
bool m_hasAutoMidiDev;
|
|
static InstrumentTrack *s_autoAssignedTrack;
|
|
|
|
IntModel m_baseNoteModel;
|
|
|
|
NotePlayHandleList m_processHandles;
|
|
|
|
FloatModel m_volumeModel;
|
|
FloatModel m_panningModel;
|
|
|
|
AudioPort m_audioPort;
|
|
|
|
FloatModel m_pitchModel;
|
|
IntModel m_pitchRangeModel;
|
|
IntModel m_effectChannelModel;
|
|
BoolModel m_useMasterPitchModel;
|
|
|
|
|
|
Instrument * m_instrument;
|
|
InstrumentSoundShaping m_soundShaping;
|
|
InstrumentFunctionArpeggio m_arpeggio;
|
|
InstrumentFunctionNoteStacking m_noteStacking;
|
|
|
|
Piano m_piano;
|
|
|
|
|
|
friend class InstrumentTrackView;
|
|
friend class InstrumentTrackWindow;
|
|
friend class NotePlayHandle;
|
|
friend class InstrumentMiscView;
|
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
class InstrumentTrackView : public TrackView
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
InstrumentTrackView( InstrumentTrack * _it, TrackContainerView* tc );
|
|
virtual ~InstrumentTrackView();
|
|
|
|
InstrumentTrackWindow * getInstrumentTrackWindow();
|
|
|
|
InstrumentTrack * model()
|
|
{
|
|
return castModel<InstrumentTrack>();
|
|
}
|
|
|
|
const InstrumentTrack * model() const
|
|
{
|
|
return castModel<InstrumentTrack>();
|
|
}
|
|
|
|
static InstrumentTrackWindow * topLevelInstrumentTrackWindow();
|
|
|
|
QMenu * midiMenu()
|
|
{
|
|
return m_midiMenu;
|
|
}
|
|
|
|
void freeInstrumentTrackWindow();
|
|
|
|
static void cleanupWindowCache();
|
|
|
|
// Create a menu for assigning/creating channels for this track
|
|
QMenu * createFxMenu( QString title, QString newFxLabel ) override;
|
|
|
|
|
|
protected:
|
|
void dragEnterEvent( QDragEnterEvent * _dee ) override;
|
|
void dropEvent( QDropEvent * _de ) override;
|
|
|
|
|
|
private slots:
|
|
void toggleInstrumentWindow( bool _on );
|
|
void activityIndicatorPressed();
|
|
void activityIndicatorReleased();
|
|
|
|
void midiInSelected();
|
|
void midiOutSelected();
|
|
void midiConfigChanged();
|
|
|
|
void assignFxLine( int channelIndex );
|
|
void createFxLine();
|
|
|
|
|
|
private:
|
|
InstrumentTrackWindow * m_window;
|
|
|
|
static QQueue<InstrumentTrackWindow *> s_windowCache;
|
|
|
|
// widgets in track-settings-widget
|
|
TrackLabelButton * m_tlb;
|
|
Knob * m_volumeKnob;
|
|
Knob * m_panningKnob;
|
|
FadeButton * m_activityIndicator;
|
|
|
|
QMenu * m_midiMenu;
|
|
|
|
QAction * m_midiInputAction;
|
|
QAction * m_midiOutputAction;
|
|
|
|
QPoint m_lastPos;
|
|
|
|
FadeButton * getActivityIndicator()
|
|
{
|
|
return m_activityIndicator;
|
|
}
|
|
|
|
friend class InstrumentTrackWindow;
|
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
class InstrumentTrackWindow : public QWidget, public ModelView,
|
|
public SerializingObjectHook
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
InstrumentTrackWindow( InstrumentTrackView * _tv );
|
|
virtual ~InstrumentTrackWindow();
|
|
|
|
// parent for all internal tab-widgets
|
|
TabWidget * tabWidgetParent()
|
|
{
|
|
return m_tabWidget;
|
|
}
|
|
|
|
InstrumentTrack * model()
|
|
{
|
|
return castModel<InstrumentTrack>();
|
|
}
|
|
|
|
const InstrumentTrack * model() const
|
|
{
|
|
return castModel<InstrumentTrack>();
|
|
}
|
|
|
|
void setInstrumentTrackView( InstrumentTrackView * _tv );
|
|
|
|
InstrumentTrackView *instrumentTrackView()
|
|
{
|
|
return m_itv;
|
|
}
|
|
|
|
|
|
PianoView * pianoView()
|
|
{
|
|
return m_pianoView;
|
|
}
|
|
|
|
static void dragEnterEventGeneric( QDragEnterEvent * _dee );
|
|
|
|
void dragEnterEvent( QDragEnterEvent * _dee ) override;
|
|
void dropEvent( QDropEvent * _de ) override;
|
|
|
|
|
|
public slots:
|
|
void textChanged( const QString & _new_name );
|
|
void toggleVisibility( bool _on );
|
|
void updateName();
|
|
void updateInstrumentView();
|
|
|
|
|
|
protected:
|
|
// capture close-events for toggling instrument-track-button
|
|
void closeEvent( QCloseEvent * _ce ) override;
|
|
void focusInEvent( QFocusEvent * _fe ) override;
|
|
|
|
void saveSettings( QDomDocument & _doc, QDomElement & _this ) override;
|
|
void loadSettings( const QDomElement & _this ) override;
|
|
|
|
|
|
protected slots:
|
|
void saveSettingsBtnClicked();
|
|
void viewNextInstrument();
|
|
void viewPrevInstrument();
|
|
|
|
private:
|
|
void modelChanged() override;
|
|
void viewInstrumentInDirection(int d);
|
|
//! adjust size of any child widget of the main tab
|
|
//! required to keep the old look when using a variable sized tab widget
|
|
void adjustTabSize(QWidget *w);
|
|
|
|
InstrumentTrack * m_track;
|
|
InstrumentTrackView * m_itv;
|
|
|
|
// widgets on the top of an instrument-track-window
|
|
QLineEdit * m_nameLineEdit;
|
|
LeftRightNav * m_leftRightNav;
|
|
Knob * m_volumeKnob;
|
|
Knob * m_panningKnob;
|
|
Knob * m_pitchKnob;
|
|
QLabel * m_pitchLabel;
|
|
LcdSpinBox* m_pitchRangeSpinBox;
|
|
QLabel * m_pitchRangeLabel;
|
|
FxLineLcdSpinBox * m_effectChannelNumber;
|
|
|
|
|
|
|
|
// tab-widget with all children
|
|
TabWidget * m_tabWidget;
|
|
PluginView * m_instrumentView;
|
|
InstrumentSoundShapingView * m_ssView;
|
|
InstrumentFunctionNoteStackingView* m_noteStackingView;
|
|
InstrumentFunctionArpeggioView* m_arpeggioView;
|
|
InstrumentMidiIOView * m_midiView;
|
|
EffectRackView * m_effectView;
|
|
InstrumentMiscView *m_miscView;
|
|
|
|
|
|
// test-piano at the bottom of every instrument-settings-window
|
|
PianoView * m_pianoView;
|
|
|
|
friend class InstrumentView;
|
|
|
|
} ;
|
|
|
|
|
|
|
|
#endif
|