Compare commits

...

46 Commits

Author SHA1 Message Date
Hyunjin Song
9c21d0b4d8 Use QPair<int, float> for control points instead of QVector<float> 2020-12-10 11:28:29 +09:00
codythecoder
0dfdbc956a Add bezier progression type to automation tracks 2020-12-10 11:28:29 +09:00
Spekular
d3cd704396 Temporary PR-Freeze message 2020-12-08 15:55:43 +01:00
Alexandre Almeida
040fb48867 Update code style for BBTrackContainer (#5812) 2020-12-08 00:25:00 +01:00
Johannes Lorenz
2f66449092 Implement Lv2 Options (#5761)
Implement `LV2_OPTIONS__options` feature and some buf-size properties.

The code currently assumes that the LMMS buffersize never changes, which
is currently true in the LMMS code base.
2020-12-08 00:12:04 +01:00
IanCaio
cd2366a21c Fix style on "SampleBuffer.cpp" and "SampleBuffer.h" (#5791)
Fix code style issues in the `SampleBuffer` class.

Remove strange comments around "not an Ogg Vorbis file"
warning.
2020-12-07 23:09:34 +01:00
Kevin Zander
118d63bada Change abs to std::abs (#5831)
This prevents GCC 6 from raising an ambiguous call error.
2020-12-07 22:42:05 +01:00
IanCaio
53a733ba66 Fixes bug where clicking on the Activity Indicator doesn't play a note (#5824) 2020-12-07 17:11:41 -03:00
Hyunjin Song
3ad0462d44 Fix too small height of the carla instrument window (#5829) 2020-12-07 13:55:50 +09:00
Alexandre Almeida
b701e82e3b Split Track.cpp and Track.h (#5806) (Fixes #5592) 2020-12-04 02:47:16 +01:00
Johannes Lorenz
ddf69feebc Lv2: Fix overflow and enum visualization
* Fix arithmetic overflow in `Lv2Ports::Meta::get()` in case min and
  max are not set
* Fix combo boxes with >16 values being wrongly visualized as knobs
* Rename `Lv2Ports::Vis` enum value `None` to `Generic`
2020-12-03 06:10:30 +01:00
Dominic Clark
827d44be32 Ensure file opened successfully when loading sample (#5816) 2020-12-03 01:31:03 +00:00
IanCaio
3c36365afa Adds support for MIDI CC events inside LMMS (#5581) 2020-12-01 22:27:37 -03:00
Dominic Clark
4f74151f00 Fix export when rendering looped section multiple times (#5814)
Co-authored-by: Hyunjin Song <tteu.ingog@gmail.com>
2020-12-01 19:38:04 +09:00
Hyunjin Song
9f0dc0fb1b Work around build failures for tests on macOS >= 10.14
This one should be removed once we export the include directory for lmms
to tests properly.
2020-12-01 19:36:17 +09:00
Hyunjin Song
d6b9853426 Tests: use C++14 as well as LMMS 2020-12-01 19:34:33 +09:00
Hyunjin Song
d73ede58a3 Remove instrument track window caching to fix related bugs (#5808) 2020-12-01 11:03:58 +09:00
Hyunjin Song
aff2ebcce0 Update CIs to macOS 10.14 and XCode 10.3 2020-12-01 11:01:39 +09:00
Hyunjin Song
c49ca376bf Fix crash on OGG export with Qt >= 5.10 (#5813) 2020-11-30 16:48:26 +09:00
Alexandre Almeida
6e081265ba Rename MidiTime to TimePos (#5684)
Fixes #4866
2020-11-29 19:46:13 +01:00
Johannes Lorenz
a2e71c81de Lv2: Use port-property "logarithmic"
This also adds more min/max checks, mostly for logarithmic scales.
Since this raised some warnings for logarithmic CV ports, the CV
metadata is now also read (but CV ports are still not supported).
2020-11-29 11:26:08 +01:00
Johannes Lorenz
7a85b4d547 Lv2Manager: Print issues uniq-ed 2020-11-29 11:26:08 +01:00
Hyunjin Song
f7128700b4 Ensure instrument window resize correctly on instrument changes (#5797) 2020-11-28 15:15:28 +09:00
Oskar Wallgren
ee7175be75 Bitinvader - Fix saving with automation and division by 0 (#5805)
* Prevent division by 0 in bitInvader::normalize().
* Save and load whole wavetable on save/load and also clear wavetable
before loading a new one.

Co-authored-by: Dominic Clark <mrdomclark@gmail.com>
Co-authored-by: Spekular <Spekularr@gmail.com>
Co-authored-by: thmueller64 <64359888+thmueller64@users.noreply.github.com>
2020-11-27 16:42:23 +01:00
Dominic Clark
246b822a6f Rework Song::processNextBuffer (#5723) 2020-11-27 13:46:06 +00:00
Hyunjin Song
9ca5497202 Improve STK rawwave path detection (#5804) 2020-11-27 11:53:42 +09:00
thmueller64
1949f93f10 Add checkboxes for selecting user and factory content (#5786)
Co-authored-by: IanCaio <iancaio_dev@hotmail.com>
Co-authored-by: Dominic Clark <mrdomclark@gmail.com>
Co-authored-by: Kevin Zander <veratil@gmail.com>
2020-11-26 22:25:32 +00:00
Dominic Clark
571c425f4a Support multiple instrument subplugin categories (#5801) 2020-11-24 23:55:10 +00:00
Spekular
ed9abe58c6 Add option to continue sidebar previews when mouse released (#5787)
* Add option to continue sidebar previews when mouse released

* Cancel non-sample previews regardless of setting
2020-11-24 21:49:54 +01:00
IanCaio
8d4bcd7105 Fixes bug on SampleBuffer::decodeSampleSF (#5796)
As requested, this PR extracts the bug fix from #5971. More
details about the bug on the mentioned PR page, but basically the
variable sf_rr was declared with the wrong type causing the conditional
that checks for errors on the loading to return true even when there
were no errors (only noticeable with DEBUG builds).
	This renames the variable and uses the correct type.
2020-11-23 04:18:17 -03:00
David CARLIER
b00adeadc5 annotate Track::getActivityIndicator implementations as override. (#5798) 2020-11-21 20:04:23 +09:00
Kumar
53b003bc8f Allow SampleTCOs/Sample Clips to be reversed (#5765)
Enable the reverse option from `SampleBuffer.cpp`, and partially change the style and make more readable `SampleBuffer.cpp`.
2020-11-21 09:56:06 +05:30
Alexandre Almeida
83e51ffc45 Remove unused stuff (#5685) 2020-11-20 15:49:15 +00:00
thmueller64
87875a18e3 Fix glitch in undo/redo of note edits via the menu (#5789) 2020-11-19 21:34:08 +01:00
dj-pixus
f26296037a Fixed Stereo Matrix icon (#5792) 2020-11-18 21:28:13 +01:00
Kumar
a42d2d2d70 Color mixer channels if they are made by a colored track (#5780)
Color mixer channels if they are made by a coloured track using the “Assign to new FX channel option.”
2020-11-16 23:02:57 +05:30
Johannes Lorenz
060d0dc5dc Lv2Proc: Check def in [min,max] when creating port 2020-11-15 20:10:51 +01:00
Johannes Lorenz
3a74bad0c9 Lv2Ports: Smash plugins with out-of-bounds defaults 2020-11-15 20:10:51 +01:00
Johannes Lorenz
1c2107f4c6 Fix missing support for lv2core#sampleRate (Fixes #5767)
This multiplies port's min/max value with the processing sample rate
that is used for the plugin. This fixes damaged audio in GLAME
Butterworth High-/Lowpass from #5767.
2020-11-15 20:10:51 +01:00
Johannes Lorenz
48bc9db71d Forbid crashing Calf Analyzer/BassEnhancer 2020-11-15 20:10:20 +01:00
Johannes Lorenz
01f2fa5c29 Introduce blacklisted plugins to Lv2 interface 2020-11-15 20:10:20 +01:00
Johannes Lorenz
7dd6a39366 Introduce blacklisted plugins to core 2020-11-15 20:10:20 +01:00
DigArtRoks
4fb66542a0 Fix for the font of truncated sidebar items (#5714). (#5777)
* Fix for the font of truncated sidebar items (#5714).

For windows platforms, retrieve the system font and set it for the FileBrowserTreeWidget. This makes sure that truncated items will use the font as non-truncated items.

* Add TODO to remove the fix when all builds use a recent enough version of qt.

* Add check on QT version and conditionally include the fix.
2020-11-14 16:45:49 +01:00
IanCaio
28a394413f Fixes bug with cloning Automation Tracks (#5732)
Fixes bug from issue #5595. When cloning an automation track, the IDs from the recently created AutomationPatterns weren't being resolved, causing them to show as disconnected automations.
	This PR fixes the issue by adding a call to AutomationPattern::resolveAllIDs() on the Track::clone() method. It also fixes the code style on that method.
2020-11-14 08:12:24 -03:00
Pause for Affliction
e1d1878108 Fix memory leak that the rpmalloc assert warns of (#5776) (Fixes #5733)
Hack to take care of the assertion sent by the rpmalloc memory manager. Creates a static "free" function for NotePlayHandleManager and then shoves it right before the program ends.

Co-authored-by: Pause for Affliction <47124830+Epsilon-13@users.noreply.github.com>
2020-11-10 12:40:53 +01:00
IanCaio
5864aea3d3 Fixes bug with cloning Automation Tracks
Fixes bug from issue #5595. When cloning an automation track, the IDs from the recently created AutomationPatterns weren't being resolved, causing them to show as disconnected automations.
	This PR fixes the issue by adding a call to AutomationPattern::resolveAllIDs() on the Track::clone() method. It also fixes the code style on that method.
2020-10-25 09:59:39 -03:00
147 changed files with 6946 additions and 5235 deletions

View File

@@ -170,7 +170,7 @@ jobs:
environment:
<<: *common_environment
macos:
xcode: "9.4.1"
xcode: "10.3.0"
steps:
- checkout
- *init

View File

@@ -22,7 +22,7 @@ matrix:
git:
depth: false
- os: osx
osx_image: xcode9.4
osx_image: xcode10.3
before_install:
# appdmg doesn't work with old Node.js
- if [ "$TRAVIS_OS_NAME" = osx ]; then nvm install 10; fi

View File

@@ -6,6 +6,8 @@
[![Join the chat at Discord](https://img.shields.io/badge/chat-on%20discord-7289DA.svg)](https://discord.gg/3sc5su7)
[![Localise on transifex](https://img.shields.io/badge/localise-on_transifex-green.svg)](https://www.transifex.com/lmms/lmms/)
**A soft PR-Freeze is currently underway to prepare for refactoring ([#5592](https://github.com/LMMS/lmms/issues/5592)). Please do not open non-essential PRs at this time.**
What is LMMS?
--------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

View File

@@ -129,6 +129,12 @@ QMenu::indicator:selected {
background-color: #747474;
}
FileBrowser QCheckBox
{
font-size: 10px;
color: white;
}
PositionLine {
qproperty-tailGradient: false;
qproperty-lineColor: rgb(255, 255, 255);

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

View File

@@ -40,6 +40,12 @@ QMdiArea {
background-color: #111314;
}
FileBrowser QCheckBox
{
font-size: 10px;
color: white;
}
Knob {
qproperty-lineInactiveColor: rgb(120, 120, 120);
qproperty-arcInactiveColor: rgba(120, 120, 120, 70);

View File

@@ -30,7 +30,7 @@
#include "JournallingObject.h"
#include "Model.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "ValueBuffer.h"
#include "MemoryManager.h"
#include "ModelVisitor.h"
@@ -281,7 +281,7 @@ public:
return false;
}
float globalAutomationValueAt( const MidiTime& time );
float globalAutomationValueAt( const TimePos& time );
void setStrictStepSize( const bool b )
{

View File

@@ -50,6 +50,7 @@ public:
}
void setModel( Model* model, bool isOldModelValid = true ) override;
void unsetModel() override;
template<typename T>
inline T value() const

View File

@@ -34,7 +34,7 @@
#include "lmms_basics.h"
#include "JournallingObject.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "AutomationPattern.h"
#include "ComboBoxModel.h"
#include "Knob.h"
@@ -56,6 +56,7 @@ class AutomationEditor : public QWidget, public JournallingObject
Q_PROPERTY(QColor beatLineColor READ beatLineColor WRITE setBeatLineColor)
Q_PROPERTY(QColor lineColor READ lineColor WRITE setLineColor)
Q_PROPERTY(QColor vertexColor READ vertexColor WRITE setVertexColor)
Q_PROPERTY(QColor controlPointColor READ controlPointColor WRITE setControlPointColor)
Q_PROPERTY(QBrush scaleColor READ scaleColor WRITE setScaleColor)
Q_PROPERTY(QBrush graphColor READ graphColor WRITE setGraphColor)
Q_PROPERTY(QColor crossColor READ crossColor WRITE setCrossColor)
@@ -91,6 +92,8 @@ public:
void setGraphColor(const QBrush & c);
QColor vertexColor() const;
void setVertexColor(const QColor & c);
QColor controlPointColor() const;
void setControlPointColor(const QColor& c);
QBrush scaleColor() const;
void setScaleColor(const QBrush & c);
QColor crossColor() const;
@@ -113,6 +116,7 @@ public slots:
protected:
typedef AutomationPattern::timeMap timeMap;
typedef AutomationPattern::controlPointTimeMap controlPointTimeMap;
void keyPressEvent(QKeyEvent * ke) override;
void leaveEvent(QEvent * e) override;
@@ -153,7 +157,7 @@ protected slots:
void pasteValues();
void deleteSelectedValues();
void updatePosition( const MidiTime & t );
void updatePosition( const TimePos & t );
void zoomingXChanged();
void zoomingYChanged();
@@ -167,6 +171,7 @@ private:
{
NONE,
MOVE_VALUE,
MOVE_CONTROL_POINT,
SELECT_VALUES,
MOVE_SELECTION
} ;
@@ -215,7 +220,7 @@ private:
QScrollBar * m_leftRightScroll;
QScrollBar * m_topBottomScroll;
MidiTime m_currentPosition;
TimePos m_currentPosition;
Actions m_action;
@@ -249,6 +254,7 @@ private:
void drawCross(QPainter & p );
void drawAutomationPoint( QPainter & p, timeMap::iterator it );
void drawControlPoint( QPainter & p, controlPointTimeMap::iterator it, float key_y );
bool inBBEditor();
QColor m_barLineColor;
@@ -256,6 +262,7 @@ private:
QColor m_lineColor;
QBrush m_graphColor;
QColor m_vertexColor;
QColor m_controlPointColor;
QBrush m_scaleColor;
QColor m_crossColor;
QColor m_backgroundShade;
@@ -265,7 +272,7 @@ private:
signals:
void currentPatternChanged();
void positionChanged( const MidiTime & );
void positionChanged( const TimePos & );
} ;
@@ -313,6 +320,7 @@ private:
QAction* m_discreteAction;
QAction* m_linearAction;
QAction* m_cubicHermiteAction;
QAction* m_bezierAction;
QAction* m_flipYAction;
QAction* m_flipXAction;

View File

@@ -27,14 +27,15 @@
#ifndef AUTOMATION_PATTERN_H
#define AUTOMATION_PATTERN_H
#include <QtCore/QMap>
#include <QtCore/QPointer>
#include <QMap>
#include <QPair>
#include <QPointer>
#include "Track.h"
#include "TrackContentObject.h"
class AutomationTrack;
class MidiTime;
class TimePos;
@@ -46,10 +47,12 @@ public:
{
DiscreteProgression,
LinearProgression,
CubicHermiteProgression
CubicHermiteProgression,
BezierProgression
} ;
typedef QMap<int, float> timeMap;
typedef QMap<int, QPair<int, float> > controlPointTimeMap;
typedef QVector<QPointer<AutomatableModel> > objectVector;
AutomationPattern( AutomationTrack * _auto_track );
@@ -74,25 +77,39 @@ public:
}
void setTension( QString _new_tension );
MidiTime timeMapLength() const;
TimePos timeMapLength() const;
void updateLength();
MidiTime putValue( const MidiTime & time,
TimePos putValue( const TimePos & time,
const float value,
const bool quantPos = true,
const bool ignoreSurroundingPoints = true );
void removeValue( const MidiTime & time );
TimePos putControlPoint( timeMap::const_iterator it,
const float _value);
void recordValue(MidiTime time, float value);
TimePos putControlPoint(timeMap::const_iterator it,
const int time, const float _value);
MidiTime setDragValue( const MidiTime & time,
TimePos putControlPoint(timeMap::const_iterator it,
const int time, const float _value, const bool flip);
void removeValue( const TimePos & time );
void recordValue(TimePos time, float value);
TimePos setDragValue( const TimePos & time,
const float value,
const bool quantPos = true,
const bool controlKey = false );
TimePos setControlPointDragValue( const TimePos & _time, const float _value, const int _x,
const bool _quant_pos = true );
void applyDragValue();
void flipControlPoint(bool flip);
bool isDragging() const
{
@@ -119,6 +136,27 @@ public:
return m_tangents;
}
inline const controlPointTimeMap & getControlPoints() const
{
return m_controlPoints;
}
inline controlPointTimeMap & getControlPoints()
{
return m_controlPoints;
}
// This is for getting the node of the control point that is being dragged
inline const timeMap::ConstIterator & getControlPointNode() const
{
return m_oldControlPointNode;
}
inline timeMap::ConstIterator & getControlPointNode()
{
return m_oldControlPointNode;
}
inline float getMin() const
{
return firstObject()->minValue<float>();
@@ -134,8 +172,8 @@ public:
return m_timeMap.isEmpty() == false;
}
float valueAt( const MidiTime & _time ) const;
float *valuesAfter( const MidiTime & _time ) const;
float valueAt( const TimePos & _time ) const;
float *valuesAfter( const TimePos & _time ) const;
const QString name() const;
@@ -160,6 +198,8 @@ public:
static int quantization() { return s_quantization; }
static void setQuantization(int q) { s_quantization = q; }
void clampControlPoints(bool clampVertical=true);
public slots:
void clear();
void objectDestroyed( jo_id_t );
@@ -169,6 +209,7 @@ public slots:
private:
void cleanObjects();
void cleanControlPoints();
void generateTangents();
void generateTangents( timeMap::const_iterator it, int numToGenerate );
float valueAt( timeMap::const_iterator v, int offset ) const;
@@ -179,12 +220,20 @@ private:
timeMap m_timeMap; // actual values
timeMap m_oldTimeMap; // old values for storing the values before setDragValue() is called.
timeMap m_tangents; // slope at each point for calculating spline
controlPointTimeMap m_controlPoints; // control points for calculating the bezier curve
controlPointTimeMap m_oldControlPoints; // old values for storing the values before setDragValue() is called.
// m_oldControlPoints is similar to m_oldTimeMap, since the control points need to be dragged as well or something
timeMap::const_iterator m_oldControlPointNode; // Which automation point was the control point connected to?
bool m_controlFlip; // If the lefthand control point is grabbed, the value must be flipped around the automation point
float m_controlPointDragOffset[2];
float m_tension;
bool m_hasAutomation;
ProgressionTypes m_progressionType;
bool m_dragging;
bool m_isRecording;
float m_lastRecordedValue;

View File

@@ -30,7 +30,7 @@
#include "AutomationPattern.h"
#include "Song.h"
#include "SongEditor.h"
#include "Track.h"
#include "TrackContentObjectView.h"
class AutomationPatternView : public TrackContentObjectView

View File

@@ -28,6 +28,7 @@
#define AUTOMATION_TRACK_H
#include "Track.h"
#include "TrackView.h"
class AutomationTrack : public Track
@@ -37,7 +38,7 @@ public:
AutomationTrack( TrackContainer* tc, bool _hidden = false );
virtual ~AutomationTrack() = default;
virtual bool play( const MidiTime & _start, const fpp_t _frames,
virtual bool play( const TimePos & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 ) override;
QString nodeName() const override
@@ -46,7 +47,7 @@ public:
}
TrackView * createView( TrackContainerView* ) override;
TrackContentObject* createTCO(const MidiTime & pos) override;
TrackContentObject* createTCO(const TimePos & pos) override;
virtual void saveTrackSpecificSettings( QDomDocument & _doc,
QDomElement & _parent ) override;

View File

@@ -26,6 +26,7 @@
#ifndef BB_EDITOR_H
#define BB_EDITOR_H
#include "Editor.h"
#include "TrackContainerView.h"

View File

@@ -31,7 +31,9 @@
#include <QtCore/QMap>
#include <QStaticText>
#include "TrackContentObjectView.h"
#include "Track.h"
#include "TrackView.h"
class TrackLabelButton;
class TrackContainer;
@@ -103,10 +105,10 @@ public:
BBTrack( TrackContainer* tc );
virtual ~BBTrack();
virtual bool play( const MidiTime & _start, const fpp_t _frames,
virtual bool play( const TimePos & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 ) override;
TrackView * createView( TrackContainerView* tcv ) override;
TrackContentObject* createTCO(const MidiTime & pos) override;
TrackContentObject* createTCO(const TimePos & pos) override;
virtual void saveTrackSpecificSettings( QDomDocument & _doc,
QDomElement & _parent ) override;

View File

@@ -38,8 +38,7 @@ public:
BBTrackContainer();
virtual ~BBTrackContainer();
virtual bool play( MidiTime _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 );
virtual bool play(TimePos start, const fpp_t frames, const f_cnt_t frameBase, int tcoNum = -1);
void updateAfterTrackAdd() override;
@@ -48,21 +47,21 @@ public:
return "bbtrackcontainer";
}
bar_t lengthOfBB( int _bb ) const;
bar_t lengthOfBB(int bb) const;
inline bar_t lengthOfCurrentBB()
{
return lengthOfBB( currentBB() );
return lengthOfBB(currentBB());
}
int numOfBBs() const;
void removeBB( int _bb );
void removeBB(int bb);
void swapBB( int _bb1, int _bb2 );
void swapBB(int bb1, int bb2);
void updateBBTrack( TrackContentObject * _tco );
void updateBBTrack(TrackContentObject * tco);
void fixIncorrectPositions();
void createTCOsForBB( int _bb );
void createTCOsForBB(int bb);
AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum) const override;
AutomatedValueMap automatedValuesAt(TimePos time, int tcoNum) const override;
public slots:
void play();

View File

@@ -35,7 +35,6 @@
#include "lmms_basics.h"
class BBTrackContainer;
class DummyTrackContainer;
class FxMixer;
class ProjectJournal;
class Mixer;
@@ -88,6 +87,8 @@ public:
return s_projectJournal;
}
static bool ignorePluginBlacklist();
#ifdef LMMS_HAVE_LV2
static class Lv2Manager * getLv2Manager()
{
@@ -100,11 +101,6 @@ public:
return s_ladspaManager;
}
static DummyTrackContainer * dummyTrackContainer()
{
return s_dummyTC;
}
static float framesPerTick()
{
return s_framesPerTick;
@@ -149,7 +145,6 @@ private:
static Song * s_song;
static BBTrackContainer * s_bbTrackContainer;
static ProjectJournal * s_projectJournal;
static DummyTrackContainer * s_dummyTC;
#ifdef LMMS_HAVE_LV2
static class Lv2Manager* s_lv2Manager;

View File

@@ -26,6 +26,7 @@
#ifndef FILE_BROWSER_H
#define FILE_BROWSER_H
#include <QCheckBox>
#include <QtCore/QDir>
#include <QtCore/QMutex>
#include <QTreeWidget>
@@ -58,7 +59,10 @@ public:
*/
FileBrowser( const QString & directories, const QString & filter,
const QString & title, const QPixmap & pm,
QWidget * parent, bool dirs_as_items = false, bool recurse = false );
QWidget * parent, bool dirs_as_items = false, bool recurse = false,
const QString& userDir = "",
const QString& factoryDir = "");
virtual ~FileBrowser() = default;
private slots:
@@ -83,6 +87,11 @@ private:
bool m_dirsAsItems;
bool m_recurse;
void addContentCheckBox();
QCheckBox* m_showUserContent = nullptr;
QCheckBox* m_showFactoryContent = nullptr;
QString m_userDir;
QString m_factoryDir;
} ;

View File

@@ -73,7 +73,13 @@ class FxChannel : public ThreadableJob
void unmuteForSolo();
// TODO C++17 and above: use std::optional insteads
void setColor (QColor newColor)
{
m_color = newColor;
m_hasColor = true;
}
// TODO C++17 and above: use std::optional instead
QColor m_color;
bool m_hasColor;

View File

@@ -28,6 +28,7 @@
#include <QtCore/QObject>
#include "lmms_export.h"
#include "lmmsconfig.h"
class QLabel;
@@ -48,6 +49,9 @@ public:
~GuiApplication();
static GuiApplication* instance();
#ifdef LMMS_BUILD_WIN32
static QFont getWin32SystemFont();
#endif
MainWindow* mainWindow() { return m_mainWindow; }
FxMixerView* fxMixerView() { return m_fxMixerView; }

View File

@@ -30,8 +30,8 @@
#include "lmms_export.h"
#include "lmms_basics.h"
#include "MemoryManager.h"
#include "MidiTime.h"
#include "Plugin.h"
#include "TimePos.h"
// forward-declarations
@@ -105,7 +105,7 @@ public:
// sub-classes can re-implement this for receiving all incoming
// MIDI-events
inline virtual bool handleMidiEvent( const MidiEvent&, const MidiTime& = MidiTime(), f_cnt_t offset = 0 )
inline virtual bool handleMidiEvent( const MidiEvent&, const TimePos& = TimePos(), f_cnt_t offset = 0 )
{
return true;
}

View File

@@ -30,6 +30,8 @@
#include "GroupBox.h"
#include "InstrumentFunctions.h"
#include "InstrumentSoundShaping.h"
#include "Midi.h"
#include "MidiCCRackView.h"
#include "MidiEventProcessor.h"
#include "MidiPort.h"
#include "NotePlayHandle.h"
@@ -38,11 +40,11 @@
#include "Pitch.h"
#include "Plugin.h"
#include "Track.h"
#include "TrackView.h"
class QLineEdit;
template<class T> class QQueue;
class InstrumentFunctionArpeggioView;
class InstrumentFunctionNoteStackingView;
class EffectRackView;
@@ -80,8 +82,8 @@ public:
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;
void processInEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) override;
void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) override;
// silence all running notes played by this track
void silenceAllNotes( bool removeIPH = false );
@@ -130,13 +132,13 @@ public:
}
// play everything in given frame-range - creates note-play-handles
virtual bool play( const MidiTime & _start, const fpp_t _frames,
virtual bool play( const TimePos & _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;
TrackContentObject* createTCO(const TimePos & pos) override;
// called by track
@@ -229,7 +231,6 @@ signals:
void newNote();
void endNote();
protected:
QString nodeName() const override
{
@@ -248,6 +249,8 @@ protected slots:
private:
void processCCEvent(int controller);
MidiPort m_midiPort;
NotePlayHandle* m_notes[NumKeys];
@@ -287,11 +290,14 @@ private:
Piano m_piano;
std::unique_ptr<BoolModel> m_midiCCEnable;
std::unique_ptr<FloatModel> m_midiCCModel[MidiControllerCount];
friend class InstrumentTrackView;
friend class InstrumentTrackWindow;
friend class NotePlayHandle;
friend class InstrumentMiscView;
friend class MidiCCRackView;
} ;
@@ -324,10 +330,6 @@ public:
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;
@@ -339,6 +341,7 @@ protected:
private slots:
void toggleInstrumentWindow( bool _on );
void toggleMidiCCRack();
void activityIndicatorPressed();
void activityIndicatorReleased();
@@ -349,12 +352,12 @@ private slots:
void assignFxLine( int channelIndex );
void createFxLine();
void handleConfigChange(QString cls, QString attr, QString value);
private:
InstrumentTrackWindow * m_window;
static QQueue<InstrumentTrackWindow *> s_windowCache;
// widgets in track-settings-widget
TrackLabelButton * m_tlb;
Knob * m_volumeKnob;
@@ -366,9 +369,11 @@ private:
QAction * m_midiInputAction;
QAction * m_midiOutputAction;
std::unique_ptr<MidiCCRackView> m_midiCCRackView;
QPoint m_lastPos;
FadeButton * getActivityIndicator()
FadeButton * getActivityIndicator() override
{
return m_activityIndicator;
}
@@ -482,6 +487,7 @@ private:
PianoView * m_pianoView;
friend class InstrumentView;
friend class InstrumentTrackView;
} ;

View File

@@ -70,7 +70,7 @@ class LMMS_EXPORT Lv2ControlBase : public LinkedModelGroups
{
public:
static Plugin::PluginTypes check(const LilvPlugin* m_plugin,
std::vector<PluginIssue> &issues, bool printIssues = false);
std::vector<PluginIssue> &issues);
const LilvPlugin* getPlugin() const { return m_plugin; }
@@ -134,7 +134,7 @@ protected:
QString nodeName() const { return "lv2controls"; }
bool hasNoteInput() const;
void handleMidiInputEvent(const class MidiEvent &event,
const class MidiTime &time, f_cnt_t offset);
const class TimePos &time, f_cnt_t offset);
private:
//! Return the DataFile settings type

View File

@@ -130,6 +130,13 @@ public:
return m_supportedFeatureURIs;
}
bool isFeatureSupported(const char* featName) const;
AutoLilvNodes findNodes(const LilvNode *subject,
const LilvNode *predicate, const LilvNode *object);
static const std::set<const char*, Lv2Manager::CmpStr>& getPluginBlacklist()
{
return pluginBlacklist;
}
private:
// general data
@@ -144,6 +151,9 @@ private:
// URID cache for fast URID access
Lv2UridCache m_uridCache;
// static
static const std::set<const char*, Lv2Manager::CmpStr> pluginBlacklist;
// functions
bool isSubclassOf(const LilvPluginClass *clvss, const char *uriStr);
};

104
include/Lv2Options.h Normal file
View File

@@ -0,0 +1,104 @@
/*
* Lv2Options.h - Lv2Options class
*
* Copyright (c) 2020-2020 Johannes Lorenz <jlsf2013$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 LV2OPTIONS_H
#define LV2OPTIONS_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_LV2
#include <cstdint>
#include <lv2/lv2plug.in/ns/ext/options/options.h>
#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "Engine.h"
#include "Lv2Manager.h"
#include "Lv2UridCache.h"
/**
Option container
References all available options for a plugin and maps them to their URIDs.
This class is used per Lv2 processor (justification in Lv2Proc::initMOptions())
The public member functions should be called in descending order:
1. supportOption: set all supported option URIDs
2. initOption: initialize options with values
3. createOptionVectors: create the option vectors required for
the feature
4. access the latter using feature()
*/
class Lv2Options
{
public:
//! Return if an option is supported by LMMS
static bool isOptionSupported(LV2_URID key);
//! Mark option as supported
static void supportOption(LV2_URID key);
//! Initialize an option
template<typename Opt, typename Arg>
void initOption(Lv2UridCache::Id key, Arg&& value,
LV2_Options_Context context = LV2_OPTIONS_INSTANCE,
std::uint32_t subject = 0)
{
const Lv2UridCache& cache = Engine::getLv2Manager()->uridCache();
initOption(cache[key], sizeof(Opt), cache[Lv2UridCache::IdForType<Opt>::value],
std::make_shared<Opt>(std::forward<Arg>(value)), context, subject);
}
//! Fill m_options and m_optionPointers with all options
void createOptionVectors();
//! Return the feature
const LV2_Options_Option* feature() const
{
return m_options.data();
}
private:
//! Initialize an option internally
void initOption(LV2_URID key,
uint32_t size,
LV2_URID type,
std::shared_ptr<void> value,
LV2_Options_Context context = LV2_OPTIONS_INSTANCE,
uint32_t subject = 0);
//! options that are supported by every processor
static std::set<LV2_URID> s_supportedOptions;
//! options + data, ordered by URID
std::map<LV2_URID, LV2_Options_Option> m_optionByUrid;
//! option storage
std::vector<LV2_Options_Option> m_options;
//! option value storage
std::map<LV2_URID, std::shared_ptr<void>> m_optionValues;
};
#endif // LMMS_HAVE_LV2
#endif // LV2OPTIONS_H

View File

@@ -61,10 +61,10 @@ enum class Type {
//! Port visualization
//! @note All Lv2 audio ports are float, this is only the visualisation
enum class Vis {
None,
Integer,
Enumeration,
Toggled
Generic, //!< nothing specific, a generic knob or slider shall be used
Integer, //!< counter
Enumeration, //!< selection from enumerated values
Toggled //!< boolean widget
};
const char* toStr(Lv2Ports::Flow pf);
@@ -106,13 +106,21 @@ struct Meta
{
Type m_type = Type::Unknown;
Flow m_flow = Flow::Unknown;
Vis m_vis = Vis::None;
Vis m_vis = Vis::Generic;
bool m_logarithmic = false;
float m_def = .0f, m_min = .0f, m_max = .0f;
bool m_optional = false;
bool m_used = true;
std::vector<PluginIssue> get(const LilvPlugin* plugin, std::size_t portNum);
float def() const { return m_def; }
float min(sample_rate_t sr) const { return m_sampleRate ? sr * m_min : m_min; }
float max(sample_rate_t sr) const { return m_sampleRate ? sr * m_max : m_max; }
private:
float m_def = .0f, m_min = .0f, m_max = .0f;
bool m_sampleRate = false;
};
struct PortBase : public Meta

View File

@@ -35,12 +35,13 @@
#include "Lv2Basics.h"
#include "Lv2Features.h"
#include "Lv2Options.h"
#include "LinkedModelGroups.h"
#include "MidiEvent.h"
#include "MidiTime.h"
#include "Plugin.h"
#include "PluginIssue.h"
#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h"
#include "TimePos.h"
// forward declare port structs/enums
namespace Lv2Ports
@@ -61,7 +62,7 @@ class Lv2Proc : public LinkedModelGroup
{
public:
static Plugin::PluginTypes check(const LilvPlugin* plugin,
std::vector<PluginIssue> &issues, bool printIssues = false);
std::vector<PluginIssue> &issues);
/*
ctor/dtor
@@ -144,7 +145,7 @@ public:
void run(fpp_t frames);
void handleMidiInputEvent(const class MidiEvent &event,
const MidiTime &time, f_cnt_t offset);
const TimePos &time, f_cnt_t offset);
/*
misc
@@ -168,6 +169,7 @@ private:
const LilvPlugin* m_plugin;
LilvInstance* m_instance;
Lv2Features m_features;
Lv2Options m_options;
// full list of ports
std::vector<std::unique_ptr<Lv2Ports::PortBase>> m_ports;
@@ -187,11 +189,12 @@ private:
ringbuffer_reader_t<struct MidiInputEvent> m_midiInputReader;
// other
static std::size_t minimumEvbufSize() { return 1 << 15; /* ardour uses this*/ }
static int32_t defaultEvbufSize() { return 1 << 15; /* ardour uses this*/ }
//! models for the controls, sorted by port symbols
std::map<std::string, AutomatableModel *> m_connectedModels;
void initMOptions(); //!< initialize m_options
void initPluginSpecificFeatures();
//! load a file in the plugin, but don't do anything in LMMS

View File

@@ -29,6 +29,7 @@
#ifdef LMMS_HAVE_LV2
#include <QtGlobal>
#include <cstdint>
//! Cached URIDs for fast access (for use in real-time code)
@@ -37,16 +38,33 @@ class Lv2UridCache
public:
enum class Id //!< ID for m_uridCache array
{
// keep it alphabetically (except "size" at the end)
atom_Float,
atom_Int,
bufsz_minBlockLength,
bufsz_maxBlockLength,
bufsz_nominalBlockLength,
bufsz_sequenceSize,
midi_MidiEvent,
param_sampleRate,
// exception to alphabetic ordering - keep at the end:
size
};
template<typename T>
struct IdForType;
//! Return URID for a cache ID
uint32_t operator[](Id id) const;
Lv2UridCache(class UridMap& mapper);
private:
uint32_t m_cache[static_cast<int>(Id::size)];
};
template<> struct Lv2UridCache::IdForType<float> { static constexpr auto value = Id::atom_Float; };
template<> struct Lv2UridCache::IdForType<std::int32_t> { static constexpr auto value = Id::atom_Int; };
#endif // LMMS_HAVE_LV2
#endif // LV2URIDCACHE_H

View File

@@ -66,7 +66,7 @@ public:
virtual void processOutEvent( const MidiEvent & _me,
const MidiTime & _time,
const TimePos & _time,
const MidiPort * _port ) override;
void applyPortMode( MidiPort * _port ) override;

View File

@@ -60,7 +60,7 @@ public:
}
virtual void processOutEvent( const MidiEvent & _me,
const MidiTime & _time,
const TimePos & _time,
const MidiPort * _port );
virtual void applyPortMode( MidiPort * _port );

40
include/MidiCCRackView.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef MIDI_CC_RACK_VIEW_H
#define MIDI_CC_RACK_VIEW_H
#include <QWidget>
#include "GroupBox.h"
#include "Knob.h"
#include "Midi.h"
#include "SerializingObject.h"
class InstrumentTrack;
class MidiCCRackView : public QWidget, public SerializingObject
{
Q_OBJECT
public:
MidiCCRackView(InstrumentTrack * track);
~MidiCCRackView() override;
void saveSettings(QDomDocument & doc, QDomElement & parent) override;
void loadSettings(const QDomElement &) override;
inline QString nodeName() const override
{
return "MidiCCRackView";
}
private slots:
void renameWindow();
private:
InstrumentTrack *m_track;
GroupBox *m_midiCCGroupBox; // MIDI CC GroupBox (used to enable disable MIDI CC)
Knob *m_controllerKnob[MidiControllerCount]; // Holds the knob widgets for each controller
};
#endif

View File

@@ -46,7 +46,7 @@ public:
// to be implemented by sub-classes
virtual void processOutEvent( const MidiEvent & _me,
const MidiTime & _time,
const TimePos & _time,
const MidiPort * _port ) = 0;
// inheriting classes can re-implement this for being able to update
@@ -141,7 +141,7 @@ protected:
private:
// this does MIDI-event-process
void processParsedEvent();
void processOutEvent( const MidiEvent& event, const MidiTime& time, const MidiPort* port ) override;
void processOutEvent( const MidiEvent& event, const TimePos& time, const MidiPort* port ) override;
// small helper function returning length of a certain event - this
// is necessary for parsing raw-MIDI-data

View File

@@ -44,10 +44,10 @@ public:
virtual ~MidiController();
virtual void processInEvent( const MidiEvent & _me,
const MidiTime & _time, f_cnt_t offset = 0 ) override;
const TimePos & _time, f_cnt_t offset = 0 ) override;
virtual void processOutEvent( const MidiEvent& _me,
const MidiTime & _time, f_cnt_t offset = 0 ) override
const TimePos & _time, f_cnt_t offset = 0 ) override
{
// No output yet
}

View File

@@ -33,27 +33,32 @@
class MidiEvent
{
public:
MidiEvent( MidiEventTypes type = MidiActiveSensing,
enum class Source { Internal, External };
MidiEvent(MidiEventTypes type = MidiActiveSensing,
int8_t channel = 0,
int16_t param1 = 0,
int16_t param2 = 0,
const void* sourcePort = NULL ) :
const void* sourcePort = nullptr,
Source source = Source::External) :
m_type( type ),
m_metaEvent( MidiMetaInvalid ),
m_channel( channel ),
m_sysExData( NULL ),
m_sourcePort( sourcePort )
m_sourcePort(sourcePort),
m_source(source)
{
m_data.m_param[0] = param1;
m_data.m_param[1] = param2;
}
MidiEvent( MidiEventTypes type, const char* sysExData, int dataLen ) :
MidiEvent(MidiEventTypes type, const char* sysExData, std::size_t dataLen, Source source = Source::External) :
m_type( type ),
m_metaEvent( MidiMetaInvalid ),
m_channel( 0 ),
m_sysExData( sysExData ),
m_sourcePort( NULL )
m_sourcePort(nullptr),
m_source(source)
{
m_data.m_sysExDataLen = dataLen;
}
@@ -64,7 +69,8 @@ public:
m_channel( other.m_channel ),
m_data( other.m_data ),
m_sysExData( other.m_sysExData ),
m_sourcePort( other.m_sourcePort )
m_sourcePort(other.m_sourcePort),
m_source(other.m_source)
{
}
@@ -190,6 +196,16 @@ public:
setParam( 0, pitchBend );
}
Source source() const
{
return m_source;
}
void setSource(Source value)
{
m_source = value;
}
private:
MidiEventTypes m_type; // MIDI event type
@@ -198,13 +214,15 @@ private:
union
{
int16_t m_param[2]; // first/second parameter (key/velocity)
uint8_t m_bytes[4]; // raw bytes
uint8_t m_bytes[4]; // raw bytes
int32_t m_sysExDataLen; // len of m_sysExData
} m_data;
const char* m_sysExData;
const void* m_sourcePort;
// Stores the source of the MidiEvent: Internal or External (hardware controllers).
Source m_source;
} ;
#endif

View File

@@ -26,8 +26,8 @@
#define MIDI_EVENT_PROCESSOR_H
#include "MidiEvent.h"
#include "MidiTime.h"
#include "MemoryManager.h"
#include "TimePos.h"
// all classes being able to process MIDI-events should inherit from this
class MidiEventProcessor
@@ -43,8 +43,8 @@ public:
}
// to be implemented by inheriting classes
virtual void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) = 0;
virtual void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) = 0;
virtual void processInEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) = 0;
virtual void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) = 0;
} ;

View File

@@ -31,7 +31,7 @@
#include <QtCore/QMap>
#include "Midi.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "AutomatableModel.h"
@@ -102,8 +102,8 @@ public:
return outputChannel() ? outputChannel() - 1 : 0;
}
void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime() );
void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime() );
void processInEvent( const MidiEvent& event, const TimePos& time = TimePos() );
void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos() );
void saveSettings( QDomDocument& doc, QDomElement& thisElement ) override;

View File

@@ -64,7 +64,7 @@ public:
virtual void processOutEvent( const MidiEvent & _me,
const MidiTime & _time,
const TimePos & _time,
const MidiPort * _port );
virtual void applyPortMode( MidiPort * _port );

View File

@@ -173,8 +173,6 @@ public:
//! Set new audio device. Old device will be deleted,
//! unless it's stored using storeAudioDevice
void setAudioDevice( AudioDevice * _dev , bool startNow );
//! See overloaded function
void setAudioDevice( AudioDevice * _dev,
const struct qualitySettings & _qs,
bool _needs_fifo,

View File

@@ -36,6 +36,7 @@ public:
virtual ~ModelView();
virtual void setModel( Model* model, bool isOldModelValid = true );
virtual void unsetModel();
Model* model()
{

View File

@@ -30,8 +30,8 @@
#include "volume.h"
#include "panning.h"
#include "MidiTime.h"
#include "SerializingObject.h"
#include "TimePos.h"
class DetuningHelper;
@@ -81,8 +81,8 @@ const float MaxDetuning = 4 * 12.0f;
class LMMS_EXPORT Note : public SerializingObject
{
public:
Note( const MidiTime & length = MidiTime( 0 ),
const MidiTime & pos = MidiTime( 0 ),
Note( const TimePos & length = TimePos( 0 ),
const TimePos & pos = TimePos( 0 ),
int key = DefaultKey,
volume_t volume = DefaultVolume,
panning_t panning = DefaultPanning,
@@ -93,9 +93,9 @@ public:
// used by GUI
inline void setSelected( const bool selected ) { m_selected = selected; }
inline void setOldKey( const int oldKey ) { m_oldKey = oldKey; }
inline void setOldPos( const MidiTime & oldPos ) { m_oldPos = oldPos; }
inline void setOldPos( const TimePos & oldPos ) { m_oldPos = oldPos; }
inline void setOldLength( const MidiTime & oldLength )
inline void setOldLength( const TimePos & oldLength )
{
m_oldLength = oldLength;
}
@@ -105,8 +105,8 @@ public:
}
void setLength( const MidiTime & length );
void setPos( const MidiTime & pos );
void setLength( const TimePos & length );
void setPos( const TimePos & pos );
void setKey( const int key );
virtual void setVolume( volume_t volume );
virtual void setPanning( panning_t panning );
@@ -138,12 +138,12 @@ public:
return m_oldKey;
}
inline MidiTime oldPos() const
inline TimePos oldPos() const
{
return m_oldPos;
}
inline MidiTime oldLength() const
inline TimePos oldLength() const
{
return m_oldLength;
}
@@ -153,23 +153,23 @@ public:
return m_isPlaying;
}
inline MidiTime endPos() const
inline TimePos endPos() const
{
const int l = length();
return pos() + l;
}
inline const MidiTime & length() const
inline const TimePos & length() const
{
return m_length;
}
inline const MidiTime & pos() const
inline const TimePos & pos() const
{
return m_pos;
}
inline MidiTime pos( MidiTime basePos ) const
inline TimePos pos( TimePos basePos ) const
{
const int bp = basePos;
return m_pos - bp;
@@ -205,7 +205,7 @@ public:
return classNodeName();
}
static MidiTime quantized( const MidiTime & m, const int qGrid );
static TimePos quantized( const TimePos & m, const int qGrid );
DetuningHelper * detuning() const
{
@@ -226,15 +226,15 @@ private:
// for piano roll editing
bool m_selected;
int m_oldKey;
MidiTime m_oldPos;
MidiTime m_oldLength;
TimePos m_oldPos;
TimePos m_oldLength;
bool m_isPlaying;
int m_key;
volume_t m_volume;
panning_t m_panning;
MidiTime m_length;
MidiTime m_pos;
TimePos m_length;
TimePos m_pos;
DetuningHelper * m_detuning;
};

View File

@@ -244,19 +244,19 @@ public:
}
/*! Process note detuning automation */
void processMidiTime( const MidiTime& time );
void processTimePos( const TimePos& time );
/*! Updates total length (m_frames) depending on a new tempo */
void resize( const bpm_t newTempo );
/*! Set song-global offset (relative to containing pattern) in order to properly perform the note detuning */
void setSongGlobalParentOffset( const MidiTime& offset )
void setSongGlobalParentOffset( const TimePos& offset )
{
m_songGlobalParentOffset = offset;
}
/*! Returns song-global offset */
const MidiTime& songGlobalParentOffset() const
const TimePos& songGlobalParentOffset() const
{
return m_songGlobalParentOffset;
}
@@ -323,7 +323,7 @@ private:
float m_unpitchedFrequency;
BaseDetuning* m_baseDetuning;
MidiTime m_songGlobalParentOffset;
TimePos m_songGlobalParentOffset;
int m_midiChannel;
Origin m_origin;
@@ -349,6 +349,7 @@ public:
NotePlayHandle::Origin origin = NotePlayHandle::OriginPattern );
static void release( NotePlayHandle * nph );
static void extend( int i );
static void free();
private:
static NotePlayHandle ** s_available;

View File

@@ -34,16 +34,10 @@
#include "Note.h"
#include "Track.h"
#include "TrackContentObjectView.h"
class QAction;
class QProgressBar;
class QPushButton;
class InstrumentTrack;
class SampleBuffer;
class LMMS_EXPORT Pattern : public TrackContentObject
@@ -128,7 +122,7 @@ protected slots:
private:
MidiTime beatPatternLength() const;
TimePos beatPatternLength() const;
void setType( PatternTypes _new_pattern_type );
void checkType();

View File

@@ -187,9 +187,9 @@ protected slots:
void pasteNotes();
bool deleteSelectedNotes();
void updatePosition(const MidiTime & t );
void updatePositionAccompany(const MidiTime & t );
void updatePositionStepRecording(const MidiTime & t );
void updatePosition(const TimePos & t );
void updatePositionAccompany(const TimePos & t );
void updatePositionStepRecording(const TimePos & t );
void zoomingChanged();
void zoomingYChanged();
@@ -266,9 +266,9 @@ private:
PianoRoll( const PianoRoll & );
virtual ~PianoRoll();
void autoScroll(const MidiTime & t );
void autoScroll(const TimePos & t );
MidiTime newNoteLen() const;
TimePos newNoteLen() const;
void shiftPos(int amount);
void shiftPos(NoteVector notes, int amount);
@@ -331,7 +331,7 @@ private:
QScrollBar * m_leftRightScroll;
QScrollBar * m_topBottomScroll;
MidiTime m_currentPosition;
TimePos m_currentPosition;
bool m_recording;
QList<Note> m_recordingNotes;
@@ -377,12 +377,12 @@ private:
// remember these values to use them
// for the next note that is set
MidiTime m_lenOfNewNotes;
TimePos m_lenOfNewNotes;
volume_t m_lastNoteVolume;
panning_t m_lastNotePanning;
//When resizing several notes, we want to calculate a common minimum length
MidiTime m_minResizeLen;
TimePos m_minResizeLen;
int m_startKey; // first key when drawing
int m_lastKey;
@@ -447,7 +447,7 @@ private:
QBrush m_blackKeyInactiveBackground;
signals:
void positionChanged( const MidiTime & );
void positionChanged( const TimePos & );
} ;

View File

@@ -33,7 +33,6 @@
class QLineEdit;
class QTreeWidget;
class QTreeWidgetItem;
class PluginBrowser : public SideBarWidget
@@ -53,8 +52,6 @@ private:
QWidget * m_view;
QTreeWidget * m_descTree;
QTreeWidgetItem * m_lmmsRoot;
QTreeWidgetItem * m_lv2Root;
};

View File

@@ -32,18 +32,29 @@
//! LMMS Plugins should use this to indicate errors
enum PluginIssueType
{
// port flow & type
unknownPortFlow,
unknownPortType,
// channel count
tooManyInputChannels,
tooManyOutputChannels,
tooManyMidiInputChannels,
tooManyMidiOutputChannels,
noOutputChannel,
// port metadata
portHasNoDef,
portHasNoMin,
portHasNoMax,
minGreaterMax,
defaultValueNotInRange,
logScaleMinMissing,
logScaleMaxMissing,
logScaleMinMaxDifferentSigns,
// features
featureNotSupported, //!< plugin requires functionality LMMS can't offer
// misc
badPortType, //!< port type not supported
blacklisted,
noIssue
};
@@ -60,6 +71,9 @@ public:
: m_issueType(it), m_info(msg)
{
}
PluginIssueType type() const { return m_issueType; }
bool operator==(const PluginIssue& other) const;
bool operator<(const PluginIssue& other) const;
friend QDebug operator<<(QDebug stream, const PluginIssue& iss);
};

View File

@@ -29,6 +29,7 @@
#include "NotePlayHandle.h"
class DataFile;
class InstrumentTrack;
class PreviewTrackContainer;

View File

@@ -62,7 +62,7 @@ public:
{
MM_OPERATORS
public:
handleState( bool _varying_pitch = false, int interpolation_mode = SRC_LINEAR );
handleState(bool varyingPitch = false, int interpolationMode = SRC_LINEAR);
virtual ~handleState();
const f_cnt_t frameIndex() const
@@ -70,9 +70,9 @@ public:
return m_frameIndex;
}
void setFrameIndex( f_cnt_t _index )
void setFrameIndex(f_cnt_t index)
{
m_frameIndex = _index;
m_frameIndex = index;
}
bool isBackwards() const
@@ -80,9 +80,9 @@ public:
return m_isBackwards;
}
void setBackwards( bool _backwards )
void setBackwards(bool backwards)
{
m_isBackwards = _backwards;
m_isBackwards = backwards;
}
int interpolationMode() const
@@ -106,21 +106,35 @@ public:
SampleBuffer();
// constructor which either loads sample _audio_file or decodes
// base64-data out of string
SampleBuffer( const QString & _audio_file, bool _is_base64_data = false );
SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames );
explicit SampleBuffer( const f_cnt_t _frames );
SampleBuffer(const QString & audioFile, bool isBase64Data = false);
SampleBuffer(const sampleFrame * data, const f_cnt_t frames);
explicit SampleBuffer(const f_cnt_t frames);
virtual ~SampleBuffer();
bool play( sampleFrame * _ab, handleState * _state,
const fpp_t _frames,
const float _freq,
const LoopMode _loopmode = LoopOff );
bool play(
sampleFrame * ab,
handleState * state,
const fpp_t frames,
const float freq,
const LoopMode loopMode = LoopOff
);
void visualize( QPainter & _p, const QRect & _dr, const QRect & _clip, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 );
inline void visualize( QPainter & _p, const QRect & _dr, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 )
void visualize(
QPainter & p,
const QRect & dr,
const QRect & clip,
f_cnt_t fromFrame = 0,
f_cnt_t toFrame = 0
);
inline void visualize(
QPainter & p,
const QRect & dr,
f_cnt_t fromFrame = 0,
f_cnt_t toFrame = 0
)
{
visualize( _p, _dr, _dr, _from_frame, _to_frame );
visualize(p, dr, dr, fromFrame, toFrame);
}
inline const QString & audioFile() const
@@ -148,22 +162,27 @@ public:
return m_loopEndFrame;
}
void setLoopStartFrame( f_cnt_t _start )
void setLoopStartFrame(f_cnt_t start)
{
m_loopStartFrame = _start;
m_loopStartFrame = start;
}
void setLoopEndFrame( f_cnt_t _end )
void setLoopEndFrame(f_cnt_t end)
{
m_loopEndFrame = _end;
m_loopEndFrame = end;
}
void setAllPointFrames( f_cnt_t _start, f_cnt_t _end, f_cnt_t _loopstart, f_cnt_t _loopend )
void setAllPointFrames(
f_cnt_t start,
f_cnt_t end,
f_cnt_t loopStart,
f_cnt_t loopEnd
)
{
m_startFrame = _start;
m_endFrame = _end;
m_loopStartFrame = _loopstart;
m_loopEndFrame = _loopend;
m_startFrame = start;
m_endFrame = end;
m_loopStartFrame = loopStart;
m_loopEndFrame = loopEnd;
}
inline f_cnt_t frames() const
@@ -193,17 +212,17 @@ public:
int sampleLength() const
{
return double( m_endFrame - m_startFrame ) / m_sampleRate * 1000;
return double(m_endFrame - m_startFrame) / m_sampleRate * 1000;
}
inline void setFrequency( float _freq )
inline void setFrequency(float freq)
{
m_frequency = _freq;
m_frequency = freq;
}
inline void setSampleRate( sample_rate_t _rate )
inline void setSampleRate(sample_rate_t rate)
{
m_sampleRate = _rate;
m_sampleRate = rate;
}
inline const sampleFrame * data() const
@@ -215,30 +234,28 @@ public:
QString openAndSetAudioFile();
QString openAndSetWaveformFile();
QString & toBase64( QString & _dst ) const;
QString & toBase64(QString & dst) const;
// protect calls from the GUI to this function with dataReadLock() and
// dataUnlock()
SampleBuffer * resample( const sample_rate_t _src_sr,
const sample_rate_t _dst_sr );
SampleBuffer * resample(const sample_rate_t srcSR, const sample_rate_t dstSR);
void normalizeSampleRate( const sample_rate_t _src_sr,
bool _keep_settings = false );
void normalizeSampleRate(const sample_rate_t srcSR, bool keepSettings = false);
// protect calls from the GUI to this function with dataReadLock() and
// dataUnlock(), out of loops for efficiency
inline sample_t userWaveSample( const float _sample ) const
inline sample_t userWaveSample(const float sample) const
{
f_cnt_t frames = m_frames;
sampleFrame * data = m_data;
const float frame = _sample * frames;
f_cnt_t f1 = static_cast<f_cnt_t>( frame ) % frames;
if( f1 < 0 )
const float frame = sample * frames;
f_cnt_t f1 = static_cast<f_cnt_t>(frame) % frames;
if (f1 < 0)
{
f1 += frames;
}
return linearInterpolate( data[f1][0], data[ (f1 + 1) % frames ][0], fraction( frame ) );
return linearInterpolate(data[f1][0], data[(f1 + 1) % frames][0], fraction(frame));
}
void dataReadLock()
@@ -253,33 +270,42 @@ public:
public slots:
void setAudioFile( const QString & _audio_file );
void loadFromBase64( const QString & _data );
void setStartFrame( const f_cnt_t _s );
void setEndFrame( const f_cnt_t _e );
void setAmplification( float _a );
void setReversed( bool _on );
void setAudioFile(const QString & audioFile);
void loadFromBase64(const QString & data);
void setStartFrame(const f_cnt_t s);
void setEndFrame(const f_cnt_t e);
void setAmplification(float a);
void setReversed(bool on);
void sampleRateChanged();
private:
static sample_rate_t mixerSampleRate();
void update( bool _keep_settings = false );
void update(bool keepSettings = false);
void convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames, int _channels);
void directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _channels);
void convertIntToFloat(int_sample_t * & ibuf, f_cnt_t frames, int channels);
void directFloatWrite(sample_t * & fbuf, f_cnt_t frames, int channels);
f_cnt_t decodeSampleSF( QString _f, sample_t * & _buf,
ch_cnt_t & _channels,
sample_rate_t & _sample_rate );
f_cnt_t decodeSampleSF(
QString fileName,
sample_t * & buf,
ch_cnt_t & channels,
sample_rate_t & samplerate
);
#ifdef LMMS_HAVE_OGGVORBIS
f_cnt_t decodeSampleOGGVorbis( QString _f, int_sample_t * & _buf,
ch_cnt_t & _channels,
sample_rate_t & _sample_rate );
f_cnt_t decodeSampleOGGVorbis(
QString fileName,
int_sample_t * & buf,
ch_cnt_t & channels,
sample_rate_t & samplerate
);
#endif
f_cnt_t decodeSampleDS( QString _f, int_sample_t * & _buf,
ch_cnt_t & _channels,
sample_rate_t & _sample_rate );
f_cnt_t decodeSampleDS(
QString fileName,
int_sample_t * & buf,
ch_cnt_t & channels,
sample_rate_t & samplerate
);
QString m_audioFile;
sampleFrame * m_origData;
@@ -296,13 +322,19 @@ private:
float m_frequency;
sample_rate_t m_sampleRate;
sampleFrame * getSampleFragment( f_cnt_t _index, f_cnt_t _frames,
LoopMode _loopmode,
sampleFrame * * _tmp,
bool * _backwards, f_cnt_t _loopstart, f_cnt_t _loopend,
f_cnt_t _end ) const;
f_cnt_t getLoopedIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const;
f_cnt_t getPingPongIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const;
sampleFrame * getSampleFragment(
f_cnt_t index,
f_cnt_t frames,
LoopMode loopMode,
sampleFrame * * tmp,
bool * backwards,
f_cnt_t loopStart,
f_cnt_t loopEnd,
f_cnt_t end
) const;
f_cnt_t getLoopedIndex(f_cnt_t index, f_cnt_t startf, f_cnt_t endf) const;
f_cnt_t getPingPongIndex(f_cnt_t index, f_cnt_t startf, f_cnt_t endf) const;
signals:

View File

@@ -29,8 +29,8 @@
#include <QtCore/QList>
#include <QtCore/QPair>
#include "MidiTime.h"
#include "PlayHandle.h"
#include "TimePos.h"
class BBTrack;
class SampleBuffer;
@@ -60,7 +60,7 @@ private:
typedef QList<QPair<sampleFrame *, f_cnt_t> > bufferList;
bufferList m_buffers;
f_cnt_t m_framesRecorded;
MidiTime m_minLength;
TimePos m_minLength;
Track * m_track;
BBTrack * m_bbTrack;

View File

@@ -33,6 +33,8 @@
#include "FxMixer.h"
#include "FxLineLcdSpinBox.h"
#include "Track.h"
#include "TrackContentObjectView.h"
#include "TrackView.h"
class EffectRackView;
class Knob;
@@ -50,7 +52,7 @@ public:
SampleTCO( Track * _track );
virtual ~SampleTCO();
void changeLength( const MidiTime & _length ) override;
void changeLength( const TimePos & _length ) override;
const QString & sampleFile() const;
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
@@ -65,7 +67,7 @@ public:
return m_sampleBuffer;
}
MidiTime sampleLength() const;
TimePos sampleLength() const;
void setSampleStartFrame( f_cnt_t startFrame );
void setSamplePlayLength( f_cnt_t length );
TrackContentObjectView * createView( TrackView * _tv ) override;
@@ -94,6 +96,7 @@ private:
signals:
void sampleChanged();
void wasReversed();
} ;
@@ -109,6 +112,7 @@ public:
public slots:
void updateSample();
void reverseSample();
@@ -137,10 +141,10 @@ public:
SampleTrack( TrackContainer* tc );
virtual ~SampleTrack();
virtual bool play( const MidiTime & _start, const fpp_t _frames,
virtual bool play( const TimePos & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 ) override;
TrackView * createView( TrackContainerView* tcv ) override;
TrackContentObject* createTCO(const MidiTime & pos) override;
TrackContentObject* createTCO(const TimePos & pos) override;
virtual void saveTrackSpecificSettings( QDomDocument & _doc,
@@ -251,7 +255,7 @@ private:
TrackLabelButton * m_tlb;
FadeButton * getActivityIndicator()
FadeButton * getActivityIndicator() override
{
return m_activityIndicator;
}

View File

@@ -75,6 +75,7 @@ private slots:
void toggleCompactTrackButtons(bool enabled);
void toggleOneInstrumentTrackWindow(bool enabled);
void toggleSideBarOnRight(bool enabled);
void toggleLetPreviewsFinish(bool enabled);
void toggleSoloLegacyBehavior(bool enabled);
void toggleMMPZ(bool enabled);
void toggleDisableBackup(bool enabled);
@@ -133,6 +134,7 @@ private:
bool m_compactTrackButtons;
bool m_oneInstrumentTrackWindow;
bool m_sideBarOnRight;
bool m_letPreviewsFinish;
bool m_soloLegacyBehavior;
bool m_MMPZ;
bool m_disableBackup;

View File

@@ -29,6 +29,8 @@
#include <QtCore/QSharedMemory>
#include <QtCore/QVector>
#include <QHash>
#include <QString>
#include "TrackContainer.h"
#include "Controller.h"
@@ -81,11 +83,11 @@ public:
bool hasErrors();
QString errorSummary();
class PlayPos : public MidiTime
class PlayPos : public TimePos
{
public:
PlayPos( const int abs = 0 ) :
MidiTime( abs ),
TimePos( abs ),
m_timeLine( NULL ),
m_currentFrame( 0.0f )
{
@@ -131,27 +133,27 @@ public:
return m_elapsedMilliSeconds[playMode];
}
inline void setToTime(MidiTime const & midiTime)
inline void setToTime(TimePos const & pos)
{
m_elapsedMilliSeconds[m_playMode] = midiTime.getTimeInMilliseconds(getTempo());
m_playPos[m_playMode].setTicks(midiTime.getTicks());
m_elapsedMilliSeconds[m_playMode] = pos.getTimeInMilliseconds(getTempo());
m_playPos[m_playMode].setTicks(pos.getTicks());
}
inline void setToTime(MidiTime const & midiTime, PlayModes playMode)
inline void setToTime(TimePos const & pos, PlayModes playMode)
{
m_elapsedMilliSeconds[playMode] = midiTime.getTimeInMilliseconds(getTempo());
m_playPos[playMode].setTicks(midiTime.getTicks());
m_elapsedMilliSeconds[playMode] = pos.getTimeInMilliseconds(getTempo());
m_playPos[playMode].setTicks(pos.getTicks());
}
inline void setToTimeByTicks(tick_t ticks)
{
m_elapsedMilliSeconds[m_playMode] = MidiTime::ticksToMilliseconds(ticks, getTempo());
m_elapsedMilliSeconds[m_playMode] = TimePos::ticksToMilliseconds(ticks, getTempo());
m_playPos[m_playMode].setTicks(ticks);
}
inline void setToTimeByTicks(tick_t ticks, PlayModes playMode)
{
m_elapsedMilliSeconds[playMode] = MidiTime::ticksToMilliseconds(ticks, getTempo());
m_elapsedMilliSeconds[playMode] = TimePos::ticksToMilliseconds(ticks, getTempo());
m_playPos[playMode].setTicks(ticks);
}
@@ -162,7 +164,7 @@ public:
inline int ticksPerBar() const
{
return MidiTime::ticksPerBar(m_timeSigModel);
return TimePos::ticksPerBar(m_timeSigModel);
}
// Returns the beat position inside the bar, 0-based
@@ -248,6 +250,10 @@ public:
{
return m_playPos[pm];
}
inline PlayPos & getPlayPos()
{
return getPlayPos(m_playMode);
}
inline const PlayPos & getPlayPos() const
{
return getPlayPos(m_playMode);
@@ -269,7 +275,7 @@ public:
}
//TODO: Add Q_DECL_OVERRIDE when Qt4 is dropped
AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const override;
AutomatedValueMap automatedValuesAt(TimePos time, int tcoNum = -1) const override;
// file management
void createNewProject();
@@ -405,7 +411,7 @@ private:
void removeAllControllers();
void processAutomations(const TrackList& tracks, MidiTime timeStart, fpp_t frames);
void processAutomations(const TrackList& tracks, TimePos timeStart, fpp_t frames);
void setModified(bool value);
@@ -458,11 +464,11 @@ private:
int m_loopRenderCount;
int m_loopRenderRemaining;
MidiTime m_exportSongBegin;
MidiTime m_exportLoopBegin;
MidiTime m_exportLoopEnd;
MidiTime m_exportSongEnd;
MidiTime m_exportEffectiveLength;
TimePos m_exportSongBegin;
TimePos m_exportLoopBegin;
TimePos m_exportLoopEnd;
TimePos m_exportSongEnd;
TimePos m_exportEffectiveLength;
friend class LmmsCore;
friend class SongEditor;

View File

@@ -80,7 +80,7 @@ public slots:
void setEditModeSelect();
void toggleProportionalSnap();
void updatePosition( const MidiTime & t );
void updatePosition( const TimePos & t );
void updatePositionLine();
void selectAllTcos( bool select );
@@ -150,7 +150,7 @@ private:
QPoint m_scrollPos;
QPoint m_mousePos;
int m_rubberBandStartTrackview;
MidiTime m_rubberbandStartMidipos;
TimePos m_rubberbandStartTimePos;
int m_currentZoomingValue;
int m_trackHeadWidth;
bool m_selectRegion;

View File

@@ -41,14 +41,14 @@ class StepRecorder : public QObject
StepRecorder(PianoRoll& pianoRoll, StepRecorderWidget& stepRecorderWidget);
void initialize();
void start(const MidiTime& currentPosition,const MidiTime& stepLength);
void start(const TimePos& currentPosition,const TimePos& stepLength);
void stop();
void notePressed(const Note & n);
void noteReleased(const Note & n);
bool keyPressEvent(QKeyEvent* ke);
bool mousePressEvent(QMouseEvent* ke);
void setCurrentPattern(Pattern* newPattern);
void setStepsLength(const MidiTime& newLength);
void setStepsLength(const TimePos& newLength);
QVector<Note*> getCurStepNotes();
@@ -73,7 +73,7 @@ class StepRecorder : public QObject
void dismissStep();
void prepareNewStep();
MidiTime getCurStepEndPos();
TimePos getCurStepEndPos();
void updateCurStepNotes();
void updateWidget();
@@ -84,11 +84,11 @@ class StepRecorder : public QObject
StepRecorderWidget& m_stepRecorderWidget;
bool m_isRecording = false;
MidiTime m_curStepStartPos = 0;
MidiTime m_curStepEndPos = 0;
TimePos m_curStepStartPos = 0;
TimePos m_curStepEndPos = 0;
MidiTime m_stepsLength;
MidiTime m_curStepLength; // current step length refers to the step currently recorded. it may defer from m_stepsLength
TimePos m_stepsLength;
TimePos m_curStepLength; // current step length refers to the step currently recorded. it may defer from m_stepsLength
// since the user can make current step larger
QTimer m_updateReleasedTimer;

View File

@@ -44,15 +44,15 @@ public:
//API used by PianoRoll
void setPixelsPerBar(int ppb);
void setCurrentPosition(MidiTime currentPosition);
void setCurrentPosition(TimePos currentPosition);
void setMargins(const QMargins &qm);
void setBottomMargin(const int marginBottom);
QMargins margins();
//API used by StepRecorder
void setStepsLength(MidiTime stepsLength);
void setStartPosition(MidiTime pos);
void setEndPosition(MidiTime pos);
void setStepsLength(TimePos stepsLength);
void setStartPosition(TimePos pos);
void setEndPosition(TimePos pos);
void showHint();
@@ -62,16 +62,16 @@ private:
int xCoordOfTick(int tick);
void drawVerLine(QPainter* painter, int x, const QColor& color, int top, int bottom);
void drawVerLine(QPainter* painter, const MidiTime& pos, const QColor& color, int top, int bottom);
void drawVerLine(QPainter* painter, const TimePos& pos, const QColor& color, int top, int bottom);
void updateBoundaries();
MidiTime m_stepsLength;
MidiTime m_curStepStartPos;
MidiTime m_curStepEndPos;
TimePos m_stepsLength;
TimePos m_curStepStartPos;
TimePos m_curStepEndPos;
int m_ppb; // pixels per bar
MidiTime m_currentPosition; // current position showed by on PianoRoll
TimePos m_currentPosition; // current position showed by on PianoRoll
QColor m_colorLineStart;
QColor m_colorLineEnd;
@@ -88,7 +88,7 @@ private:
const int m_marginRight;
signals:
void positionChanged(const MidiTime & t);
void positionChanged(const TimePos & t);
} ;
#endif //STEP_RECOREDER_WIDGET_H

View File

@@ -73,7 +73,7 @@ public:
TimeLineWidget(int xoff, int yoff, float ppb, Song::PlayPos & pos,
const MidiTime & begin, Song::PlayModes mode, QWidget * parent);
const TimePos & begin, Song::PlayModes mode, QWidget * parent);
virtual ~TimeLineWidget();
inline QColor const & getBarLineColor() const { return m_barLineColor; }
@@ -123,23 +123,23 @@ public:
return m_loopPoints == LoopPointsEnabled;
}
inline const MidiTime & loopBegin() const
inline const TimePos & loopBegin() const
{
return ( m_loopPos[0] < m_loopPos[1] ) ?
m_loopPos[0] : m_loopPos[1];
}
inline const MidiTime & loopEnd() const
inline const TimePos & loopEnd() const
{
return ( m_loopPos[0] > m_loopPos[1] ) ?
m_loopPos[0] : m_loopPos[1];
}
inline void savePos( const MidiTime & pos )
inline void savePos( const TimePos & pos )
{
m_savedPos = pos;
}
inline const MidiTime & savedPos() const
inline const TimePos & savedPos() const
{
return m_savedPos;
}
@@ -162,10 +162,10 @@ public:
return "timeline";
}
inline int markerX( const MidiTime & _t ) const
inline int markerX( const TimePos & _t ) const
{
return m_xOffset + static_cast<int>( ( _t - m_begin ) *
m_ppb / MidiTime::ticksPerBar() );
m_ppb / TimePos::ticksPerBar() );
}
signals:
@@ -175,10 +175,10 @@ signals:
public slots:
void updatePosition( const MidiTime & );
void updatePosition( const TimePos & );
void updatePosition()
{
updatePosition( MidiTime() );
updatePosition( TimePos() );
}
void toggleAutoScroll( int _n );
void toggleLoopPoints( int _n );
@@ -218,11 +218,11 @@ private:
int m_posMarkerX;
float m_ppb;
Song::PlayPos & m_pos;
const MidiTime & m_begin;
const TimePos & m_begin;
const Song::PlayModes m_mode;
MidiTime m_loopPos[2];
TimePos m_loopPos[2];
MidiTime m_savedPos;
TimePos m_savedPos;
TextFloat * m_hint;
@@ -242,7 +242,7 @@ private:
signals:
void positionChanged( const MidiTime & _t );
void positionChanged( const TimePos & _t );
void loopPointStateLoaded( int _n );
void positionMarkerMoved();
void loadBehaviourAtStop( int _n );

View File

@@ -1,6 +1,6 @@
/*
* MidiTime.h - declaration of class MidiTime which provides data type for
* position- and length-variables
* TimePos.h - declaration of class TimePos which provides data type for
* position- and length-variables
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net
*
@@ -24,8 +24,8 @@
*/
#ifndef MIDI_TIME_H
#define MIDI_TIME_H
#ifndef TIME_POS_H
#define TIME_POS_H
#include <QtGlobal>
@@ -40,13 +40,15 @@ const int DefaultBeatsPerBar = DefaultTicksPerBar / DefaultStepsPerBar;
class MeterModel;
/**
Represents a time signature, in which the numerator is the number of beats
in a bar, while the denominator is the type of note representing a beat.
Example: 6/8 means 6 beats in a bar with each beat having a duration of one 8th-note.
*/
class LMMS_EXPORT TimeSig
{
public:
// in a time signature,
// the numerator represents the number of beats in a measure.
// the denominator indicates which type of note represents a beat.
// example: 6/8 means 6 beats in a measure, where each beat has duration equal to one 8th-note.
TimeSig( int num, int denom );
TimeSig( const MeterModel &model );
int numerator() const;
@@ -57,17 +59,20 @@ private:
};
class LMMS_EXPORT MidiTime
/**
Represents a position in time or length of a note or event, in ticks, beats, and bars
*/
class LMMS_EXPORT TimePos
{
public:
MidiTime( const bar_t bar, const tick_t ticks );
MidiTime( const tick_t ticks = 0 );
TimePos( const bar_t bar, const tick_t ticks );
TimePos( const tick_t ticks = 0 );
MidiTime quantize(float) const;
MidiTime toAbsoluteBar() const;
TimePos quantize(float) const;
TimePos toAbsoluteBar() const;
MidiTime& operator+=( const MidiTime& time );
MidiTime& operator-=( const MidiTime& time );
TimePos& operator+=( const TimePos& time );
TimePos& operator-=( const TimePos& time );
// return the bar, rounded down and 0-based
bar_t getBar() const;
@@ -92,12 +97,12 @@ public:
double getTimeInMilliseconds( bpm_t beatsPerMinute ) const;
static MidiTime fromFrames( const f_cnt_t frames, const float framesPerTick );
static TimePos fromFrames( const f_cnt_t frames, const float framesPerTick );
static tick_t ticksPerBar();
static tick_t ticksPerBar( const TimeSig &sig );
static int stepsPerBar();
static void setTicksPerBar( tick_t tpt );
static MidiTime stepPosition( int step );
static TimePos stepPosition( int step );
static double ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute );
static double ticksToMilliseconds( double ticks, bpm_t beatsPerMinute );

View File

@@ -1,6 +1,5 @@
/*
* Track.h - declaration of classes concerning tracks -> necessary for all
* track-like objects (beat/bassline, sample-track...)
* Track.h - declaration of Track class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -26,43 +25,22 @@
#ifndef TRACK_H
#define TRACK_H
#include <QtCore/QVector>
#include <QtCore/QList>
#include <QWidget>
#include <QSize>
#include <QColor>
#include <QMimeData>
#include "lmms_basics.h"
#include "MidiTime.h"
#include "Rubberband.h"
#include "JournallingObject.h"
#include "AutomatableModel.h"
#include "ModelView.h"
#include "DataFile.h"
#include "FadeButton.h"
#include "JournallingObject.h"
#include "lmms_basics.h"
class QMenu;
class QPushButton;
class PixmapButton;
class TextFloat;
class Track;
class TrackContentObjectView;
class TimePos;
class TrackContainer;
class TrackContainerView;
class TrackContentWidget;
class TrackContentObject;
class TrackView;
const int DEFAULT_SETTINGS_WIDGET_WIDTH = 224;
const int TRACK_OP_WIDTH = 78;
// This shaves 150-ish pixels off track buttons,
// ruled from config: ui.compacttrackbuttons
const int DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT = 96;
const int TRACK_OP_WIDTH_COMPACT = 62;
/*! The minimum track height in pixels
*
* Tracks can be resized by shift-dragging anywhere inside the track
@@ -71,483 +49,10 @@ const int TRACK_OP_WIDTH_COMPACT = 62;
const int MINIMAL_TRACK_HEIGHT = 32;
const int DEFAULT_TRACK_HEIGHT = 32;
const int TCO_BORDER_WIDTH = 2;
char const *const FILENAME_FILTER = "[\\0000-\x1f\"*/:<>?\\\\|\x7f]";
class LMMS_EXPORT TrackContentObject : public Model, public JournallingObject
{
Q_OBJECT
MM_OPERATORS
mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel);
mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel);
public:
TrackContentObject( Track * track );
virtual ~TrackContentObject();
inline Track * getTrack() const
{
return m_track;
}
inline const QString & name() const
{
return m_name;
}
inline void setName( const QString & name )
{
m_name = name;
emit dataChanged();
}
QString displayName() const override
{
return name();
}
inline const MidiTime & startPosition() const
{
return m_startPosition;
}
inline MidiTime endPosition() const
{
const int sp = m_startPosition;
return sp + m_length;
}
inline const MidiTime & length() const
{
return m_length;
}
inline void setAutoResize( const bool r )
{
m_autoResize = r;
}
inline const bool getAutoResize() const
{
return m_autoResize;
}
QColor color() const
{
return m_color;
}
void setColor( const QColor & c )
{
m_color = c;
}
bool hasColor();
void useCustomClipColor( bool b );
bool usesCustomClipColor()
{
return m_useCustomClipColor;
}
virtual void movePosition( const MidiTime & pos );
virtual void changeLength( const MidiTime & length );
virtual TrackContentObjectView * createView( TrackView * tv ) = 0;
inline void selectViewOnCreate( bool select )
{
m_selectViewOnCreate = select;
}
inline bool getSelectViewOnCreate()
{
return m_selectViewOnCreate;
}
/// Returns true if and only if a->startPosition() < b->startPosition()
static bool comparePosition(const TrackContentObject* a, const TrackContentObject* b);
MidiTime startTimeOffset() const;
void setStartTimeOffset( const MidiTime &startTimeOffset );
void updateColor();
// Will copy the state of a TCO to another TCO
static void copyStateTo( TrackContentObject *src, TrackContentObject *dst );
public slots:
void toggleMute();
signals:
void lengthChanged();
void positionChanged();
void destroyedTCO();
void trackColorChanged();
private:
enum Actions
{
NoAction,
Move,
Resize
} ;
Track * m_track;
QString m_name;
MidiTime m_startPosition;
MidiTime m_length;
MidiTime m_startTimeOffset;
BoolModel m_mutedModel;
BoolModel m_soloModel;
bool m_autoResize;
bool m_selectViewOnCreate;
QColor m_color;
bool m_useCustomClipColor;
friend class TrackContentObjectView;
} ;
class TrackContentObjectView : public selectableObject, public ModelView
{
Q_OBJECT
// theming qproperties
Q_PROPERTY( QColor mutedColor READ mutedColor WRITE setMutedColor )
Q_PROPERTY( QColor mutedBackgroundColor READ mutedBackgroundColor WRITE setMutedBackgroundColor )
Q_PROPERTY( QColor selectedColor READ selectedColor WRITE setSelectedColor )
Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
Q_PROPERTY( QColor textBackgroundColor READ textBackgroundColor WRITE setTextBackgroundColor )
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 );
virtual ~TrackContentObjectView();
bool fixedTCOs();
inline TrackContentObject * getTrackContentObject()
{
return m_tco;
}
inline TrackView * getTrackView()
{
return m_trackView;
}
// qproperty access func
QColor mutedColor() const;
QColor mutedBackgroundColor() const;
QColor selectedColor() const;
QColor textColor() const;
QColor textBackgroundColor() const;
QColor textShadowColor() const;
QColor BBPatternBackground() const;
bool gradient() const;
void setMutedColor( const QColor & c );
void setMutedBackgroundColor( const QColor & c );
void setSelectedColor( const QColor & c );
void setTextColor( const QColor & c );
void setTextBackgroundColor( const QColor & c );
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();
void setNeedsUpdate( bool b );
// Method to get a QVector of TCOs to be affected by a context menu action
QVector<TrackContentObjectView *> getClickedTCOs();
// Methods to remove, copy, cut, paste and mute a QVector of TCO views
void copy( QVector<TrackContentObjectView *> tcovs );
void cut( QVector<TrackContentObjectView *> tcovs );
void paste();
// remove and toggleMute are static because they don't depend
// being called from a particular TCO view, but can be called anywhere as long
// as a valid TCO view list is given, while copy/cut require an instance for
// some metadata to be written to the clipboard.
static void remove( QVector<TrackContentObjectView *> tcovs );
static void toggleMute( QVector<TrackContentObjectView *> tcovs );
QColor getColorForDisplay( QColor );
public slots:
virtual bool close();
void remove();
void update() override;
void changeClipColor();
void useTrackColor();
protected:
enum ContextMenuAction
{
Remove,
Cut,
Copy,
Paste,
Mute
};
virtual void constructContextMenu( QMenu * )
{
}
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void leaveEvent( QEvent * e ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void resizeEvent( QResizeEvent * re ) override
{
m_needsUpdate = true;
selectableObject::resizeEvent( re );
}
float pixelsPerBar();
DataFile createTCODataFiles(const QVector<TrackContentObjectView *> & tcos) const;
virtual void paintTextLabel(QString const & text, QPainter & painter);
protected slots:
void updateLength();
void updatePosition();
private:
enum Actions
{
NoAction,
Move,
MoveSelection,
Resize,
ResizeLeft,
CopySelection,
ToggleSelected
} ;
static TextFloat * s_textFloat;
TrackContentObject * m_tco;
TrackView * m_trackView;
Actions m_action;
QPoint m_initialMousePos;
QPoint m_initialMouseGlobalPos;
MidiTime m_initialTCOPos;
MidiTime m_initialTCOEnd;
QVector<MidiTime> m_initialOffsets;
TextFloat * m_hint;
// qproperty fields
QColor m_mutedColor;
QColor m_mutedBackgroundColor;
QColor m_selectedColor;
QColor m_textColor;
QColor m_textBackgroundColor;
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;
inline void setInitialPos( QPoint pos )
{
m_initialMousePos = pos;
m_initialMouseGlobalPos = mapToGlobal( pos );
m_initialTCOPos = m_tco->startPosition();
m_initialTCOEnd = m_initialTCOPos + m_tco->length();
}
void setInitialOffsets();
bool mouseMovedDistance( QMouseEvent * me, int distance );
MidiTime draggedTCOPos( QMouseEvent * me );
} ;
class TrackContentWidget : public QWidget, public JournallingObject
{
Q_OBJECT
// qproperties for track background gradients
Q_PROPERTY( QBrush darkerColor READ darkerColor WRITE setDarkerColor )
Q_PROPERTY( QBrush lighterColor READ lighterColor WRITE setLighterColor )
Q_PROPERTY( QBrush gridColor READ gridColor WRITE setGridColor )
Q_PROPERTY( QBrush embossColor READ embossColor WRITE setEmbossColor )
public:
TrackContentWidget( TrackView * parent );
virtual ~TrackContentWidget();
/*! \brief Updates the background tile pixmap. */
void updateBackground();
void addTCOView( TrackContentObjectView * tcov );
void removeTCOView( TrackContentObjectView * tcov );
void removeTCOView( int tcoNum )
{
if( tcoNum >= 0 && tcoNum < m_tcoViews.size() )
{
removeTCOView( m_tcoViews[tcoNum] );
}
}
bool canPasteSelection( MidiTime tcoPos, const QDropEvent *de );
bool canPasteSelection( MidiTime tcoPos, const QMimeData *md, bool allowSameBar = false );
bool pasteSelection( MidiTime tcoPos, QDropEvent * de );
bool pasteSelection( MidiTime tcoPos, const QMimeData * md, bool skipSafetyCheck = false );
MidiTime endPosition( const MidiTime & posStart );
// qproperty access methods
QBrush darkerColor() const;
QBrush lighterColor() const;
QBrush gridColor() const;
QBrush embossColor() const;
void setDarkerColor( const QBrush & c );
void setLighterColor( const QBrush & c );
void setGridColor( const QBrush & c );
void setEmbossColor( const QBrush & c);
public slots:
void update();
void changePosition( const MidiTime & newPos = MidiTime( -1 ) );
protected:
enum ContextMenuAction
{
Paste
};
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( QContextMenuEvent * cme, ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
void resizeEvent( QResizeEvent * re ) override;
QString nodeName() const override
{
return "trackcontentwidget";
}
void saveSettings( QDomDocument& doc, QDomElement& element ) override
{
Q_UNUSED(doc)
Q_UNUSED(element)
}
void loadSettings( const QDomElement& element ) override
{
Q_UNUSED(element)
}
private:
Track * getTrack();
MidiTime getPosition( int mouseX );
TrackView * m_trackView;
typedef QVector<TrackContentObjectView *> tcoViewVector;
tcoViewVector m_tcoViews;
QPixmap m_background;
// qproperty fields
QBrush m_darkerColor;
QBrush m_lighterColor;
QBrush m_gridColor;
QBrush m_embossColor;
} ;
class TrackOperationsWidget : public QWidget
{
Q_OBJECT
public:
TrackOperationsWidget( TrackView * parent );
~TrackOperationsWidget();
protected:
void mousePressEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
private slots:
void cloneTrack();
void removeTrack();
void updateMenu();
void changeTrackColor();
void randomTrackColor();
void resetTrackColor();
void useTrackColor();
void toggleRecording(bool on);
void recordingOn();
void recordingOff();
void clearTrack();
private:
TrackView * m_trackView;
QPushButton * m_trackOps;
PixmapButton * m_muteBtn;
PixmapButton * m_soloBtn;
friend class TrackView;
signals:
void trackRemovalScheduled( TrackView * t );
void colorChanged( QColor & c );
void colorParented();
void colorReset();
} ;
// base-class for all tracks
//! Base-class for all tracks
class LMMS_EXPORT Track : public Model, public JournallingObject
{
Q_OBJECT
@@ -584,12 +89,12 @@ public:
return m_type;
}
virtual bool play( const MidiTime & start, const fpp_t frames,
virtual bool play( const TimePos & start, const fpp_t frames,
const f_cnt_t frameBase, int tcoNum = -1 ) = 0;
virtual TrackView * createView( TrackContainerView * view ) = 0;
virtual TrackContentObject * createTCO( const MidiTime & pos ) = 0;
virtual TrackContentObject * createTCO( const TimePos & pos ) = 0;
virtual void saveTrackSpecificSettings( QDomDocument & doc,
QDomElement & parent ) = 0;
@@ -618,15 +123,15 @@ public:
{
return m_trackContentObjects;
}
void getTCOsInRange( tcoVector & tcoV, const MidiTime & start,
const MidiTime & end );
void getTCOsInRange( tcoVector & tcoV, const TimePos & start,
const TimePos & end );
void swapPositionOfTCOs( int tcoNum1, int tcoNum2 );
void createTCOsForBB( int bb );
void insertBar( const MidiTime & pos );
void removeBar( const MidiTime & pos );
void insertBar( const TimePos & pos );
void removeBar( const TimePos & pos );
bar_t length() const;
@@ -729,122 +234,4 @@ signals:
class TrackView : public QWidget, public ModelView, public JournallingObject
{
Q_OBJECT
public:
TrackView( Track * _track, TrackContainerView* tcv );
virtual ~TrackView();
inline const Track * getTrack() const
{
return m_track;
}
inline Track * getTrack()
{
return m_track;
}
inline TrackContainerView* trackContainerView()
{
return m_trackContainerView;
}
inline TrackOperationsWidget * getTrackOperationsWidget()
{
return &m_trackOperationsWidget;
}
inline QWidget * getTrackSettingsWidget()
{
return &m_trackSettingsWidget;
}
inline TrackContentWidget * getTrackContentWidget()
{
return &m_trackContentWidget;
}
bool isMovingTrack() const
{
return m_action == MoveTrack;
}
virtual void update();
// Create a menu for assigning/creating channels for this track
// Currently instrument track and sample track supports it
virtual QMenu * createFxMenu(QString title, QString newFxLabel);
public slots:
virtual bool close();
protected:
void modelChanged() override;
void saveSettings( QDomDocument& doc, QDomElement& element ) override
{
Q_UNUSED(doc)
Q_UNUSED(element)
}
void loadSettings( const QDomElement& element ) override
{
Q_UNUSED(element)
}
QString nodeName() const override
{
return "trackview";
}
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
void resizeEvent( QResizeEvent * re ) override;
private:
enum Actions
{
NoAction,
MoveTrack,
ResizeTrack
} ;
Track * m_track;
TrackContainerView * m_trackContainerView;
TrackOperationsWidget m_trackOperationsWidget;
QWidget m_trackSettingsWidget;
TrackContentWidget m_trackContentWidget;
Actions m_action;
virtual FadeButton * getActivityIndicator()
{
return nullptr;
}
void setIndicatorMute(FadeButton* indicator, bool muted);
friend class TrackLabelButton;
private slots:
void createTCOView( TrackContentObject * tco );
void muteChanged();
} ;
#endif

View File

@@ -93,13 +93,13 @@ public:
return m_TrackContainerType;
}
virtual AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const;
virtual AutomatedValueMap automatedValuesAt(TimePos time, int tcoNum = -1) const;
signals:
void trackAdded( Track * _track );
protected:
static AutomatedValueMap automatedValuesFromTracks(const TrackList &tracks, MidiTime timeStart, int tcoNum = -1);
static AutomatedValueMap automatedValuesFromTracks(const TrackList &tracks, TimePos timeStart, int tcoNum = -1);
mutable QReadWriteLock m_tracksMutex;
@@ -115,30 +115,4 @@ private:
} ;
class DummyTrackContainer : public TrackContainer
{
public:
DummyTrackContainer();
virtual ~DummyTrackContainer()
{
}
QString nodeName() const override
{
return "DummyTrackContainer";
}
InstrumentTrack * dummyInstrumentTrack()
{
return m_dummyInstrumentTrack;
}
private:
InstrumentTrack * m_dummyInstrumentTrack;
} ;
#endif

View File

@@ -31,12 +31,15 @@
#include <QWidget>
#include <QThread>
#include "Track.h"
#include "JournallingObject.h"
#include "InstrumentTrack.h"
#include "ModelView.h"
#include "Rubberband.h"
#include "TrackView.h"
class QVBoxLayout;
class InstrumentTrack;
class TrackContainer;
@@ -57,7 +60,7 @@ public:
return m_scrollArea;
}
inline const MidiTime & currentPosition() const
inline const TimePos & currentPosition() const
{
return m_currentPosition;
}
@@ -143,7 +146,7 @@ protected:
void resizeEvent( QResizeEvent * ) override;
MidiTime m_currentPosition;
TimePos m_currentPosition;
private:
@@ -182,7 +185,7 @@ private:
signals:
void positionChanged( const MidiTime & _pos );
void positionChanged( const TimePos & _pos );
} ;

View File

@@ -0,0 +1,183 @@
/*
* TrackConteintObject.h - declaration of TrackContentObject class
*
* 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 TRACK_CONTENT_OBJECT_H
#define TRACK_CONTENT_OBJECT_H
#include <QColor>
#include "AutomatableModel.h"
#include "lmms_basics.h"
class Track;
class TrackContentObjectView;
class TrackContainer;
class TrackView;
class LMMS_EXPORT TrackContentObject : public Model, public JournallingObject
{
Q_OBJECT
MM_OPERATORS
mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel);
mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel);
public:
TrackContentObject( Track * track );
virtual ~TrackContentObject();
inline Track * getTrack() const
{
return m_track;
}
inline const QString & name() const
{
return m_name;
}
inline void setName( const QString & name )
{
m_name = name;
emit dataChanged();
}
QString displayName() const override
{
return name();
}
inline const TimePos & startPosition() const
{
return m_startPosition;
}
inline TimePos endPosition() const
{
const int sp = m_startPosition;
return sp + m_length;
}
inline const TimePos & length() const
{
return m_length;
}
inline void setAutoResize( const bool r )
{
m_autoResize = r;
}
inline const bool getAutoResize() const
{
return m_autoResize;
}
QColor color() const
{
return m_color;
}
void setColor( const QColor & c )
{
m_color = c;
}
bool hasColor();
void useCustomClipColor( bool b );
bool usesCustomClipColor()
{
return m_useCustomClipColor;
}
virtual void movePosition( const TimePos & pos );
virtual void changeLength( const TimePos & length );
virtual TrackContentObjectView * createView( TrackView * tv ) = 0;
inline void selectViewOnCreate( bool select )
{
m_selectViewOnCreate = select;
}
inline bool getSelectViewOnCreate()
{
return m_selectViewOnCreate;
}
/// Returns true if and only if a->startPosition() < b->startPosition()
static bool comparePosition(const TrackContentObject* a, const TrackContentObject* b);
TimePos startTimeOffset() const;
void setStartTimeOffset( const TimePos &startTimeOffset );
void updateColor();
// Will copy the state of a TCO to another TCO
static void copyStateTo( TrackContentObject *src, TrackContentObject *dst );
public slots:
void toggleMute();
signals:
void lengthChanged();
void positionChanged();
void destroyedTCO();
void trackColorChanged();
private:
enum Actions
{
NoAction,
Move,
Resize
} ;
Track * m_track;
QString m_name;
TimePos m_startPosition;
TimePos m_length;
TimePos m_startTimeOffset;
BoolModel m_mutedModel;
BoolModel m_soloModel;
bool m_autoResize;
bool m_selectViewOnCreate;
QColor m_color;
bool m_useCustomClipColor;
friend class TrackContentObjectView;
} ;
#endif

View File

@@ -0,0 +1,218 @@
/*
* TrackContentObjectView.h - declaration of TrackContentObjectView class
*
* 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 TRACK_CONTENT_OBJECT_VIEW_H
#define TRACK_CONTENT_OBJECT_VIEW_H
#include <QtCore/QVector>
#include "ModelView.h"
#include "Rubberband.h"
#include "TrackContentObject.h"
class QMenu;
class QContextMenuEvent;
class DataFile;
class TextFloat;
class TrackContentObject;
class TrackView;
class TrackContentObjectView : public selectableObject, public ModelView
{
Q_OBJECT
// theming qproperties
Q_PROPERTY( QColor mutedColor READ mutedColor WRITE setMutedColor )
Q_PROPERTY( QColor mutedBackgroundColor READ mutedBackgroundColor WRITE setMutedBackgroundColor )
Q_PROPERTY( QColor selectedColor READ selectedColor WRITE setSelectedColor )
Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
Q_PROPERTY( QColor textBackgroundColor READ textBackgroundColor WRITE setTextBackgroundColor )
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 );
virtual ~TrackContentObjectView();
bool fixedTCOs();
inline TrackContentObject * getTrackContentObject()
{
return m_tco;
}
inline TrackView * getTrackView()
{
return m_trackView;
}
// qproperty access func
QColor mutedColor() const;
QColor mutedBackgroundColor() const;
QColor selectedColor() const;
QColor textColor() const;
QColor textBackgroundColor() const;
QColor textShadowColor() const;
QColor BBPatternBackground() const;
bool gradient() const;
void setMutedColor( const QColor & c );
void setMutedBackgroundColor( const QColor & c );
void setSelectedColor( const QColor & c );
void setTextColor( const QColor & c );
void setTextBackgroundColor( const QColor & c );
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();
void setNeedsUpdate( bool b );
// Method to get a QVector of TCOs to be affected by a context menu action
QVector<TrackContentObjectView *> getClickedTCOs();
// Methods to remove, copy, cut, paste and mute a QVector of TCO views
void copy( QVector<TrackContentObjectView *> tcovs );
void cut( QVector<TrackContentObjectView *> tcovs );
void paste();
// remove and toggleMute are static because they don't depend
// being called from a particular TCO view, but can be called anywhere as long
// as a valid TCO view list is given, while copy/cut require an instance for
// some metadata to be written to the clipboard.
static void remove( QVector<TrackContentObjectView *> tcovs );
static void toggleMute( QVector<TrackContentObjectView *> tcovs );
QColor getColorForDisplay( QColor );
public slots:
virtual bool close();
void remove();
void update() override;
void changeClipColor();
void useTrackColor();
protected:
enum ContextMenuAction
{
Remove,
Cut,
Copy,
Paste,
Mute
};
virtual void constructContextMenu( QMenu * )
{
}
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void leaveEvent( QEvent * e ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void resizeEvent( QResizeEvent * re ) override
{
m_needsUpdate = true;
selectableObject::resizeEvent( re );
}
float pixelsPerBar();
DataFile createTCODataFiles(const QVector<TrackContentObjectView *> & tcos) const;
virtual void paintTextLabel(QString const & text, QPainter & painter);
protected slots:
void updateLength();
void updatePosition();
private:
enum Actions
{
NoAction,
Move,
MoveSelection,
Resize,
ResizeLeft,
CopySelection,
ToggleSelected
} ;
static TextFloat * s_textFloat;
TrackContentObject * m_tco;
TrackView * m_trackView;
Actions m_action;
QPoint m_initialMousePos;
QPoint m_initialMouseGlobalPos;
TimePos m_initialTCOPos;
TimePos m_initialTCOEnd;
QVector<TimePos> m_initialOffsets;
TextFloat * m_hint;
// qproperty fields
QColor m_mutedColor;
QColor m_mutedBackgroundColor;
QColor m_selectedColor;
QColor m_textColor;
QColor m_textBackgroundColor;
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;
inline void setInitialPos( QPoint pos )
{
m_initialMousePos = pos;
m_initialMouseGlobalPos = mapToGlobal( pos );
m_initialTCOPos = m_tco->startPosition();
m_initialTCOEnd = m_initialTCOPos + m_tco->length();
}
void setInitialOffsets();
bool mouseMovedDistance( QMouseEvent * me, int distance );
TimePos draggedTCOPos( QMouseEvent * me );
} ;
#endif

View File

@@ -0,0 +1,142 @@
/*
* TrackContentWidget.h - declaration of TrackContentWidget class
*
* 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 TRACK_CONTENT_WIDGET_H
#define TRACK_CONTENT_WIDGET_H
#include <QWidget>
#include "JournallingObject.h"
#include "TimePos.h"
class QMimeData;
class Track;
class TrackContentObjectView;
class TrackView;
class TrackContentWidget : public QWidget, public JournallingObject
{
Q_OBJECT
// qproperties for track background gradients
Q_PROPERTY( QBrush darkerColor READ darkerColor WRITE setDarkerColor )
Q_PROPERTY( QBrush lighterColor READ lighterColor WRITE setLighterColor )
Q_PROPERTY( QBrush gridColor READ gridColor WRITE setGridColor )
Q_PROPERTY( QBrush embossColor READ embossColor WRITE setEmbossColor )
public:
TrackContentWidget( TrackView * parent );
virtual ~TrackContentWidget();
/*! \brief Updates the background tile pixmap. */
void updateBackground();
void addTCOView( TrackContentObjectView * tcov );
void removeTCOView( TrackContentObjectView * tcov );
void removeTCOView( int tcoNum )
{
if( tcoNum >= 0 && tcoNum < m_tcoViews.size() )
{
removeTCOView( m_tcoViews[tcoNum] );
}
}
bool canPasteSelection( TimePos tcoPos, const QDropEvent *de );
bool canPasteSelection( TimePos tcoPos, const QMimeData *md, bool allowSameBar = false );
bool pasteSelection( TimePos tcoPos, QDropEvent * de );
bool pasteSelection( TimePos tcoPos, const QMimeData * md, bool skipSafetyCheck = false );
TimePos endPosition( const TimePos & posStart );
// qproperty access methods
QBrush darkerColor() const;
QBrush lighterColor() const;
QBrush gridColor() const;
QBrush embossColor() const;
void setDarkerColor( const QBrush & c );
void setLighterColor( const QBrush & c );
void setGridColor( const QBrush & c );
void setEmbossColor( const QBrush & c);
public slots:
void update();
void changePosition( const TimePos & newPos = TimePos( -1 ) );
protected:
enum ContextMenuAction
{
Paste
};
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( QContextMenuEvent * cme, ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
void resizeEvent( QResizeEvent * re ) override;
QString nodeName() const override
{
return "trackcontentwidget";
}
void saveSettings( QDomDocument& doc, QDomElement& element ) override
{
Q_UNUSED(doc)
Q_UNUSED(element)
}
void loadSettings( const QDomElement& element ) override
{
Q_UNUSED(element)
}
private:
Track * getTrack();
TimePos getPosition( int mouseX );
TrackView * m_trackView;
typedef QVector<TrackContentObjectView *> tcoViewVector;
tcoViewVector m_tcoViews;
QPixmap m_background;
// qproperty fields
QBrush m_darkerColor;
QBrush m_lighterColor;
QBrush m_gridColor;
QBrush m_embossColor;
} ;
#endif

View File

@@ -0,0 +1,79 @@
/*
* TrackOperationsWidget.h - declaration of TrackOperationsWidget class
*
* 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 TRACK_OPERATIONS_WIDGET_H
#define TRACK_OPERATIONS_WIDGET_H
#include <QWidget>
class QPushButton;
class PixmapButton;
class TrackView;
class TrackOperationsWidget : public QWidget
{
Q_OBJECT
public:
TrackOperationsWidget( TrackView * parent );
~TrackOperationsWidget();
protected:
void mousePressEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
private slots:
void cloneTrack();
void removeTrack();
void updateMenu();
void changeTrackColor();
void randomTrackColor();
void resetTrackColor();
void useTrackColor();
void toggleRecording(bool on);
void recordingOn();
void recordingOff();
void clearTrack();
private:
TrackView * m_trackView;
QPushButton * m_trackOps;
PixmapButton * m_muteBtn;
PixmapButton * m_soloBtn;
friend class TrackView;
signals:
void trackRemovalScheduled( TrackView * t );
void colorChanged( QColor & c );
void colorParented();
void colorReset();
} ;
#endif

173
include/TrackView.h Normal file
View File

@@ -0,0 +1,173 @@
/*
* TrackView.h - declaration of TrackView class
*
* 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 TRACK_VIEW_H
#define TRACK_VIEW_H
#include <QWidget>
#include "JournallingObject.h"
#include "ModelView.h"
#include "TrackContentWidget.h"
#include "TrackOperationsWidget.h"
class QMenu;
class FadeButton;
class Track;
class TrackContainerView;
class TrackContentObject;
const int DEFAULT_SETTINGS_WIDGET_WIDTH = 224;
const int TRACK_OP_WIDTH = 78;
// This shaves 150-ish pixels off track buttons,
// ruled from config: ui.compacttrackbuttons
const int DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT = 96;
const int TRACK_OP_WIDTH_COMPACT = 62;
const int TCO_BORDER_WIDTH = 2;
class TrackView : public QWidget, public ModelView, public JournallingObject
{
Q_OBJECT
public:
TrackView( Track * _track, TrackContainerView* tcv );
virtual ~TrackView();
inline const Track * getTrack() const
{
return m_track;
}
inline Track * getTrack()
{
return m_track;
}
inline TrackContainerView* trackContainerView()
{
return m_trackContainerView;
}
inline TrackOperationsWidget * getTrackOperationsWidget()
{
return &m_trackOperationsWidget;
}
inline QWidget * getTrackSettingsWidget()
{
return &m_trackSettingsWidget;
}
inline TrackContentWidget * getTrackContentWidget()
{
return &m_trackContentWidget;
}
bool isMovingTrack() const
{
return m_action == MoveTrack;
}
virtual void update();
// Create a menu for assigning/creating channels for this track
// Currently instrument track and sample track supports it
virtual QMenu * createFxMenu(QString title, QString newFxLabel);
public slots:
virtual bool close();
protected:
void modelChanged() override;
void saveSettings( QDomDocument& doc, QDomElement& element ) override
{
Q_UNUSED(doc)
Q_UNUSED(element)
}
void loadSettings( const QDomElement& element ) override
{
Q_UNUSED(element)
}
QString nodeName() const override
{
return "trackview";
}
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
void resizeEvent( QResizeEvent * re ) override;
private:
enum Actions
{
NoAction,
MoveTrack,
ResizeTrack
} ;
Track * m_track;
TrackContainerView * m_trackContainerView;
TrackOperationsWidget m_trackOperationsWidget;
QWidget m_trackSettingsWidget;
TrackContentWidget m_trackContentWidget;
Actions m_action;
virtual FadeButton * getActivityIndicator()
{
return nullptr;
}
void setIndicatorMute(FadeButton* indicator, bool muted);
friend class TrackLabelButton;
private slots:
void createTCOView( TrackContentObject * tco );
void muteChanged();
} ;
#endif

View File

@@ -134,7 +134,7 @@ void Lv2Instrument::loadFile(const QString &file)
#ifdef LV2_INSTRUMENT_USE_MIDI
bool Lv2Instrument::handleMidiEvent(
const MidiEvent &event, const MidiTime &time, f_cnt_t offset)
const MidiEvent &event, const TimePos &time, f_cnt_t offset)
{
// this function can be called from GUI threads while the plugin is running
// handleMidiInputEvent will use a thread-safe ringbuffer

View File

@@ -66,7 +66,7 @@ public:
bool hasNoteInput() const override { return Lv2ControlBase::hasNoteInput(); }
#ifdef LV2_INSTRUMENT_USE_MIDI
bool handleMidiEvent(const MidiEvent &event,
const MidiTime &time = MidiTime(), f_cnt_t offset = 0) override;
const TimePos &time = TimePos(), f_cnt_t offset = 0) override;
#else
void playNote(NotePlayHandle *nph, sampleFrame *) override;
#endif

View File

@@ -35,6 +35,7 @@
#include "lmms_math.h"
#include "TrackContainer.h"
#include "BBTrack.h"
#include "DataFile.h"
#include "InstrumentTrack.h"
#include "LocaleHelper.h"

View File

@@ -43,7 +43,7 @@
#include "Instrument.h"
#include "GuiApplication.h"
#include "MainWindow.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "debug.h"
#include "Song.h"
@@ -160,7 +160,7 @@ public:
AutomationTrack * at;
AutomationPattern * ap;
MidiTime lastPos;
TimePos lastPos;
smfMidiCC & create( TrackContainer* tc, QString tn )
{
@@ -187,11 +187,11 @@ public:
}
smfMidiCC & putValue( MidiTime time, AutomatableModel * objModel, float value )
smfMidiCC & putValue( TimePos time, AutomatableModel * objModel, float value )
{
if( !ap || time > lastPos + DefaultTicksPerBar )
{
MidiTime pPos = MidiTime( time.getBar(), 0 );
TimePos pPos = TimePos( time.getBar(), 0 );
ap = dynamic_cast<AutomationPattern*>(
at->createTCO(pPos));
ap->addObject( objModel );
@@ -200,7 +200,7 @@ public:
lastPos = time;
time = time - ap->startPosition();
ap->putValue( time, value, false );
ap->changeLength( MidiTime( time.getBar() + 1, 0 ) );
ap->changeLength( TimePos( time.getBar() + 1, 0 ) );
return *this;
}
@@ -278,14 +278,14 @@ public:
void splitPatterns()
{
Pattern * newPattern = nullptr;
MidiTime lastEnd(0);
TimePos lastEnd(0);
p->rearrangeAllNotes();
for (auto n : p->notes())
{
if (!newPattern || n->pos() > lastEnd + DefaultTicksPerBar)
{
MidiTime pPos = MidiTime(n->pos().getBar(), 0);
TimePos pPos = TimePos(n->pos().getBar(), 0);
newPattern = dynamic_cast<Pattern*>(it->createTCO(pPos));
}
lastEnd = n->pos() + n->length();

View File

@@ -293,7 +293,7 @@ int OpulenzInstrument::pushVoice(int v) {
return i;
}
bool OpulenzInstrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset )
bool OpulenzInstrument::handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset )
{
emulatorMutex.lock();
int key, vel, voice, tmp_pb;

View File

@@ -56,7 +56,7 @@ public:
return IsSingleStreamed | IsMidiBased;
}
virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset = 0 );
virtual bool handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset = 0 );
virtual void play( sampleFrame * _working_buffer );
void saveSettings( QDomDocument & _doc, QDomElement & _this );

View File

@@ -168,7 +168,7 @@ void VectorView::paintEvent(QPaintEvent *event)
// To better preserve shapes, the log scale is applied to the distance from origin,
// not the individual channels.
const float distance = sqrt(inLeft * inLeft + inRight * inRight);
const float distanceLog = log10(1 + 9 * abs(distance));
const float distanceLog = log10(1 + 9 * std::abs(distance));
const float angleCos = inLeft / distance;
const float angleSin = inRight / distance;
left = distanceLog * angleCos * (activeSize - 1) / 4;
@@ -222,7 +222,7 @@ void VectorView::paintEvent(QPaintEvent *event)
float inRight = inBuffer[frame][1] * m_zoom;
if (logScale) {
const float distance = sqrt(inLeft * inLeft + inRight * inRight);
const float distanceLog = log10(1 + 9 * abs(distance));
const float distanceLog = log10(1 + 9 * std::abs(distance));
const float angleCos = inLeft / distance;
const float angleSin = inRight / distance;
left = distanceLog * angleCos * (activeSize - 1) / 4;

View File

@@ -44,6 +44,8 @@
#include "plugin_export.h"
static const int wavetableSize = 200;
extern "C"
{
@@ -72,8 +74,8 @@ bSynth::bSynth( float * _shape, NotePlayHandle * _nph, bool _interpolation,
sample_rate( _sample_rate ),
interpolation( _interpolation)
{
sample_shape = new float[200];
for (int i=0; i < 200; ++i)
sample_shape = new float[wavetableSize];
for (int i=0; i < wavetableSize; ++i)
{
sample_shape[i] = _shape[i] * _factor;
}
@@ -138,12 +140,12 @@ sample_t bSynth::nextStringSample( float sample_length )
bitInvader::bitInvader( InstrumentTrack * _instrument_track ) :
Instrument( _instrument_track, &bitinvader_plugin_descriptor ),
m_sampleLength( 128, 4, 200, 1, this, tr( "Sample length" ) ),
m_graph( -1.0f, 1.0f, 200, this ),
m_sampleLength(128, 4, wavetableSize, 1, this, tr("Sample length")),
m_graph(-1.0f, 1.0f, wavetableSize, this),
m_interpolation( false, this ),
m_normalize( false, this )
{
lengthChanged();
m_graph.setWaveToSine();
@@ -177,8 +179,8 @@ void bitInvader::saveSettings( QDomDocument & _doc, QDomElement & _this )
// Save sample shape base64-encoded
QString sampleString;
base64::encode( (const char *)m_graph.samples(),
m_graph.length() * sizeof(float), sampleString );
base64::encode((const char *)m_graph.samples(),
wavetableSize * sizeof(float), sampleString);
_this.setAttribute( "sampleShape", sampleString );
@@ -194,6 +196,9 @@ void bitInvader::saveSettings( QDomDocument & _doc, QDomElement & _this )
void bitInvader::loadSettings( const QDomElement & _this )
{
// Clear wavetable before loading a new
m_graph.clear();
// Load sample length
m_sampleLength.loadSettings( _this, "sampleLength" );
@@ -204,8 +209,9 @@ void bitInvader::loadSettings( const QDomElement & _this )
char * dst = 0;
base64::decode( _this.attribute( "sampleShape"), &dst, &size );
m_graph.setLength( sampleLength );
m_graph.setSamples( (float*) dst );
m_graph.setLength(size / sizeof(float));
m_graph.setSamples(reinterpret_cast<float*>(dst));
m_graph.setLength(sampleLength);
delete[] dst;
// Load LED normalize
@@ -240,7 +246,7 @@ void bitInvader::samplesChanged( int _begin, int _end )
void bitInvader::normalize()
{
// analyze
float max = 0;
float max = std::numeric_limits<float>::epsilon();
const float* samples = m_graph.samples();
for(int i=0; i < m_graph.length(); i++)
{

View File

@@ -355,7 +355,7 @@ void CarlaInstrument::play(sampleFrame* workingBuffer)
instrumentTrack()->processAudioBuffer(workingBuffer, bufsize, NULL);
}
bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const MidiTime&, f_cnt_t offset)
bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const TimePos&, f_cnt_t offset)
{
const QMutexLocker ml(&fMutex);

View File

@@ -72,7 +72,7 @@ public:
virtual void saveSettings(QDomDocument& doc, QDomElement& parent);
virtual void loadSettings(const QDomElement& elem);
virtual void play(sampleFrame* workingBuffer);
virtual bool handleMidiEvent(const MidiEvent& event, const MidiTime& time, f_cnt_t offset);
virtual bool handleMidiEvent(const MidiEvent& event, const TimePos& time, f_cnt_t offset);
virtual PluginView* instantiateView(QWidget* parent);
signals:

View File

@@ -48,7 +48,6 @@ float frnd(float range)
#include "ToolTip.h"
#include "Song.h"
#include "MidiEvent.h"
#include "MidiTime.h"
#include "Mixer.h"
#include "embed.h"

View File

@@ -1,4 +1,4 @@
INCLUDE(BuildPlugin)
BUILD_PLUGIN(stereomatrix stereo_matrix.cpp stereomatrix_controls.cpp stereomatrix_control_dialog.cpp stereo_matrix.h stereomatrix_controls.h stereomatrix_control_dialog.h MOCFILES stereomatrix_controls.h stereomatrix_control_dialog.h EMBEDDED_RESOURCES artwork.png)
BUILD_PLUGIN(stereomatrix stereo_matrix.cpp stereomatrix_controls.cpp stereomatrix_control_dialog.cpp stereo_matrix.h stereomatrix_controls.h stereomatrix_control_dialog.h MOCFILES stereomatrix_controls.h stereomatrix_control_dialog.h EMBEDDED_RESOURCES artwork.png logo.png)

View File

@@ -411,7 +411,7 @@ void vestigeInstrument::play( sampleFrame * _buf )
bool vestigeInstrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset )
bool vestigeInstrument::handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset )
{
m_pluginMutex.lock();
if( m_plugin != NULL )

View File

@@ -67,7 +67,7 @@ public:
return IsSingleStreamed | IsMidiBased;
}
virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset = 0 );
virtual bool handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset = 0 );
virtual PluginView * instantiateView( QWidget * _parent );

View File

@@ -351,7 +351,7 @@ void ZynAddSubFxInstrument::play( sampleFrame * _buf )
bool ZynAddSubFxInstrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset )
bool ZynAddSubFxInstrument::handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset )
{
// do not forward external MIDI Control Change events if the according
// LED is not checked

View File

@@ -70,7 +70,7 @@ public:
virtual void play( sampleFrame * _working_buffer );
virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 );
virtual bool handleMidiEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 );
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
virtual void loadSettings( const QDomElement & _this );

View File

@@ -708,7 +708,7 @@ void AutomatableModel::reset()
float AutomatableModel::globalAutomationValueAt( const MidiTime& time )
float AutomatableModel::globalAutomationValueAt( const TimePos& time )
{
// get patterns that connect to this model
QVector<AutomationPattern *> patterns = AutomationPattern::patternsForModel( this );
@@ -720,7 +720,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time )
else
{
// of those patterns:
// find the patterns which overlap with the miditime position
// find the patterns which overlap with the time position
QVector<AutomationPattern *> patternsInRange;
for( QVector<AutomationPattern *>::ConstIterator it = patterns.begin(); it != patterns.end(); it++ )
{
@@ -738,7 +738,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time )
latestPattern = patternsInRange[0];
}
else
// if we find no patterns at the exact miditime, we need to search for the last pattern before time and use that
// if we find no patterns at the exact time, we need to search for the last pattern before time and use that
{
int latestPosition = 0;

View File

@@ -51,7 +51,7 @@ AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) :
m_isRecording( false ),
m_lastRecordedValue( 0 )
{
changeLength( MidiTime( 1, 0 ) );
changeLength( TimePos( 1, 0 ) );
if( getTrack() )
{
switch( getTrack()->trackContainer()->type() )
@@ -110,7 +110,7 @@ bool AutomationPattern::addObject( AutomatableModel * _obj, bool _search_dup )
if( m_objects.isEmpty() && hasAutomation() == false )
{
// then initialize first value
putValue( MidiTime(0), _obj->inverseScaledValue( _obj->value<float>() ), false );
putValue( TimePos(0), _obj->inverseScaledValue( _obj->value<float>() ), false );
}
m_objects += _obj;
@@ -132,7 +132,8 @@ void AutomationPattern::setProgressionType(
{
if ( _new_progression_type == DiscreteProgression ||
_new_progression_type == LinearProgression ||
_new_progression_type == CubicHermiteProgression )
_new_progression_type == CubicHermiteProgression ||
_new_progression_type == BezierProgression )
{
m_progressionType = _new_progression_type;
emit dataChanged();
@@ -176,9 +177,9 @@ const AutomationPattern::objectVector& AutomationPattern::objects() const
MidiTime AutomationPattern::timeMapLength() const
TimePos AutomationPattern::timeMapLength() const
{
MidiTime one_bar = MidiTime(1, 0);
TimePos one_bar = TimePos(1, 0);
if (m_timeMap.isEmpty()) { return one_bar; }
timeMap::const_iterator it = m_timeMap.end();
@@ -187,7 +188,7 @@ MidiTime AutomationPattern::timeMapLength() const
// return length as a whole bar to prevent disappearing TCO
if (last_tick == 0) { return one_bar; }
return MidiTime(last_tick);
return TimePos(last_tick);
}
@@ -202,14 +203,55 @@ void AutomationPattern::updateLength()
MidiTime AutomationPattern::putValue( const MidiTime & time,
TimePos AutomationPattern::putControlPoint( timeMap::const_iterator it,
const int time, const float _value, const bool flip )
{
if (flip)
{
putControlPoint( it, 2 * it.key() - time, 2 * it.value() - _value );
}
else
{
putControlPoint( it, time, _value );
}
return it.key();
}
/* If we are only given the value and automation point
then figure out where to put the control point */
TimePos AutomationPattern::putControlPoint(timeMap::const_iterator it,
const float _value)
{
// Insert control point at the automation point
return putControlPoint( it, (float)it.key() + 50, _value );
}
TimePos AutomationPattern::putControlPoint(timeMap::const_iterator it,
const int time, const float _value)
{
m_controlPoints.remove( it.key() );
m_controlPoints[it.key()] = {time, _value};
clampControlPoints();
return it.key();
}
TimePos AutomationPattern::putValue( const TimePos & time,
const float value,
const bool quantPos,
const bool ignoreSurroundingPoints )
{
cleanObjects();
MidiTime newTime = quantPos ?
TimePos newTime = quantPos ?
Note::quantized( time, quantization() ) :
time;
@@ -225,6 +267,9 @@ MidiTime AutomationPattern::putValue( const MidiTime & time,
AutomationPattern::removeValue( i );
}
}
putControlPoint(it, value);
clampControlPoints();
if( it != m_timeMap.begin() )
{
--it;
@@ -241,12 +286,13 @@ MidiTime AutomationPattern::putValue( const MidiTime & time,
void AutomationPattern::removeValue( const MidiTime & time )
void AutomationPattern::removeValue( const TimePos & time )
{
cleanObjects();
m_timeMap.remove( time );
m_tangents.remove( time );
m_controlPoints.remove( time );
timeMap::const_iterator it = m_timeMap.lowerBound( time );
if( it != m_timeMap.begin() )
{
@@ -261,7 +307,7 @@ void AutomationPattern::removeValue( const MidiTime & time )
void AutomationPattern::recordValue(MidiTime time, float value)
void AutomationPattern::recordValue(TimePos time, float value)
{
if( value != m_lastRecordedValue )
{
@@ -286,31 +332,87 @@ void AutomationPattern::recordValue(MidiTime time, float value)
* @param true to snip x position
* @return
*/
MidiTime AutomationPattern::setDragValue( const MidiTime & time,
TimePos AutomationPattern::setDragValue( const TimePos & time,
const float value,
const bool quantPos,
const bool controlKey )
{
//cleanControlPoints();
if( m_dragging == false )
{
MidiTime newTime = quantPos ?
TimePos newTime = quantPos ?
Note::quantized( time, quantization() ) :
time;
if ( m_timeMap.contains( newTime ) )
{
// Set the offset for the control point, so it gets dragged around with the automation point
m_controlPointDragOffset[0] = (float)m_controlPoints[newTime].first - (float)newTime;
m_controlPointDragOffset[1] = m_controlPoints[newTime].second - m_timeMap[newTime];
}
else
{
m_controlPointDragOffset[0] = 50;
m_controlPointDragOffset[1] = 0;
}
this->removeValue( newTime );
m_oldTimeMap = m_timeMap;
m_oldControlPoints = m_controlPoints;
m_dragging = true;
}
//Restore to the state before it the point were being dragged
m_timeMap = m_oldTimeMap;
m_controlPoints = m_oldControlPoints;
for( timeMap::const_iterator it = m_timeMap.begin(); it != m_timeMap.end(); ++it )
{
generateTangents( it, 3 );
}
return this->putValue( time, value, quantPos, controlKey );
// Put the new automation point down
TimePos returnValue = this->putValue( time, value, quantPos, controlKey );
// Put a new control point down at an offset
m_controlPoints.remove( returnValue );
putControlPoint(m_timeMap.find( returnValue ), (float)returnValue + m_controlPointDragOffset[0],
value + m_controlPointDragOffset[1]);
clampControlPoints();
return returnValue;
}
TimePos AutomationPattern::setControlPointDragValue( const TimePos & _time, const float _value, const int _x,
const bool _quant_pos)
{
if( m_dragging == false )
{
TimePos newTime = _quant_pos ?
Note::quantized( _time, quantization() ) :
_time;
m_controlPoints.remove( newTime );
m_oldControlPointNode = m_timeMap.find( newTime );
m_dragging = true;
}
return this->putControlPoint(m_oldControlPointNode, _x, _value, m_controlFlip);
}
/**
* @breif If the control point grabbed is on the left of the automation point,
* be flipped in order to get the control points actual location.
* @param should the value be flipped or not
*/
void AutomationPattern::flipControlPoint(bool flip)
{
m_controlFlip = flip;
}
@@ -327,7 +429,7 @@ void AutomationPattern::applyDragValue()
float AutomationPattern::valueAt( const MidiTime & _time ) const
float AutomationPattern::valueAt( const TimePos & _time ) const
{
if( m_timeMap.isEmpty() )
{
@@ -370,7 +472,7 @@ float AutomationPattern::valueAt( timeMap::const_iterator v, int offset ) const
((v+1).key() - v.key());
return v.value() + offset * slope;
}
else /* CubicHermiteProgression */
else if( m_progressionType == CubicHermiteProgression )
{
// Implements a Cubic Hermite spline as explained at:
// http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Unit_interval_.280.2C_1.29
@@ -390,12 +492,61 @@ float AutomationPattern::valueAt( timeMap::const_iterator v, int offset ) const
+ ( -2*pow(t,3) + 3*pow(t,2) ) * (v+1).value()
+ ( pow(t,3) - pow(t,2) ) * m2;
}
else /* BezierProgression */
{
/* Formula goes as such:
Automation points: (x0, y0), (x3, y3)
Relative control points: (x1, y1), (x2, y2)
Where the control points are BETWEEN the automation points.
(This isn't the case in this program, so the second control point must be "flipped"
around its automation point)
x = ( (1-t)^3 * x0 ) + ( 3 * (1-t)^2 * t * x1 ) + ( 3 * (1-t) * t^2 * x2 ) + ( t^3 * x3 )
y = ( (1-t)^3 * y0 ) + ( 3 * (1-t)^2 * t * y1 ) + ( 3 * (1-t) * t^2 * y2 ) + ( t^3 * y3 )
0 <= t <= 1
*/
int numValues = (v+1).key() - v.key();
// The x values are essentially twice the distance from their control points
// to make up for their range being limited.
int targetX1 = ( m_controlPoints[v.key()].first - v.key() ) * 2;
int targetX2 = ( 3 * (v+1).key() - 2 * m_controlPoints[(v+1).key()].first - v.key() );
// The y values are the actual y values. Maybe this should be doubled,
// but it doesn't seem necessary to me.
float targetY1 = m_controlPoints[v.key()].second;
float targetY2 = 2*(v+1).value() - m_controlPoints[(v+1).key()].second;
// To find the y value on the curve at a certain x, we first have to find the t (between 0 and 1) that gives the x
float t = 0;
float x = 3 * pow((1-t), 2) * t * targetX1 + 3 * (1-t) * pow(t, 2) * targetX2 + pow(t, 3) * numValues;
while (offset > x)
{
t += 0.05;
x = 3 * pow((1-t), 2) * t * targetX1 + 3 * (1-t) * pow(t, 2) * targetX2 + pow(t, 3) * numValues;
}
float ratio = x;
float y1 = pow((1-t),3) * v.value() + 3 * pow((1-t),2) * t * targetY1 +
3 * (1-t) * pow(t,2) * targetY2 + pow(t,3) * (v+1).value();
t -= 0.05;
float y2 = pow((1-t),3) * v.value() + 3 * pow((1-t),2) * t * targetY1 +
3 * (1-t) * pow(t,2) * targetY2 + pow(t,3) * (v+1).value();
x = 3 * pow((1-t), 2) * t * targetX1 + 3 * (1-t) * pow(t, 2) * targetX2 + pow(t, 3) * numValues;
// Ratio is how we get the linear extrapolation between points
// We have to get the ratio of how close this point is to its left compared to right
ratio = (offset - x) / (ratio - x);
return (ratio)*y1 + (1-ratio)*y2;
}
}
float *AutomationPattern::valuesAfter( const MidiTime & _time ) const
float *AutomationPattern::valuesAfter( const TimePos & _time ) const
{
timeMap::ConstIterator v = m_timeMap.lowerBound( _time );
if( v == m_timeMap.end() || (v+1) == m_timeMap.end() )
@@ -436,12 +587,16 @@ void AutomationPattern::flipY( int min, int max )
if ( min < 0 )
{
tempValue = valueAt( ( iterate + i ).key() ) * -1;
putValue( MidiTime( (iterate + i).key() ) , tempValue, false);
putValue( TimePos( (iterate + i).key() ) , tempValue, false);
tempValue = m_controlPoints[(iterate + i).key()].second * -1;
m_controlPoints[(iterate + i).key()].second = tempValue;
}
else
{
tempValue = max - valueAt( ( iterate + i ).key() );
putValue( MidiTime( (iterate + i).key() ) , tempValue, false);
putValue( TimePos( (iterate + i).key() ) , tempValue, false);
tempValue = max - m_controlPoints[(iterate + i).key()].second;
m_controlPoints[(iterate + i).key()].second = tempValue;
}
}
@@ -463,6 +618,7 @@ void AutomationPattern::flipY()
void AutomationPattern::flipX( int length )
{
timeMap tempMap;
controlPointTimeMap tempControlPoints;
timeMap::ConstIterator iterate = m_timeMap.lowerBound(0);
float tempValue = 0;
@@ -480,12 +636,17 @@ void AutomationPattern::flipX( int length )
if ( realLength < length )
{
tempValue = valueAt( ( iterate + numPoints ).key() );
putValue( MidiTime( length ) , tempValue, false);
putValue( TimePos( length ) , tempValue, false);
numPoints++;
for( int i = 0; i <= numPoints; i++ )
{
tempValue = valueAt( ( iterate + i ).key() );
MidiTime newTime = MidiTime( length - ( iterate + i ).key() );
TimePos newTime = TimePos( length - ( iterate + i ).key() );
int newControlPointX = -( iterate + i ).key() + m_controlPoints[( iterate + i ).key()].first + newTime;
tempControlPoints[newTime] = {newControlPointX,
2*tempValue - m_controlPoints[( iterate + i ).key()].second};
tempMap[newTime] = tempValue;
}
}
@@ -494,15 +655,19 @@ void AutomationPattern::flipX( int length )
for( int i = 0; i <= numPoints; i++ )
{
tempValue = valueAt( ( iterate + i ).key() );
MidiTime newTime;
TimePos newTime;
int newControlPointX = -( iterate + i ).key() + m_controlPoints[( iterate + i ).key()].first + newTime;
tempControlPoints[newTime] = {newControlPointX,
2*tempValue - m_controlPoints[( iterate + i ).key()].second};
if ( ( iterate + i ).key() <= length )
{
newTime = MidiTime( length - ( iterate + i ).key() );
newTime = TimePos( length - ( iterate + i ).key() );
}
else
{
newTime = MidiTime( ( iterate + i ).key() );
newTime = TimePos( ( iterate + i ).key() );
}
tempMap[newTime] = tempValue;
}
@@ -514,14 +679,20 @@ void AutomationPattern::flipX( int length )
{
tempValue = valueAt( ( iterate + i ).key() );
cleanObjects();
MidiTime newTime = MidiTime( realLength - ( iterate + i ).key() );
TimePos newTime = TimePos( realLength - ( iterate + i ).key() );
int newControlPointX = -( iterate + i ).key() + m_controlPoints[( iterate + i ).key()].first + newTime;
tempMap[newTime] = tempValue;
tempControlPoints[newTime] = {newControlPointX,
2*tempValue - m_controlPoints[( iterate + i ).key()].second};
}
}
m_timeMap.clear();
m_controlPoints.clear();
m_timeMap = tempMap;
m_controlPoints = tempControlPoints;
generateTangents();
emit dataChanged();
@@ -553,6 +724,16 @@ void AutomationPattern::saveSettings( QDomDocument & _doc, QDomElement & _this )
_this.appendChild( element );
}
for( controlPointTimeMap::const_iterator it = m_controlPoints.begin();
it != m_controlPoints.end(); ++it )
{
QDomElement element = _doc.createElement( "ctrlpnt" );
element.setAttribute( "pos", it.key() );
element.setAttribute( "value1", it.value().first );
element.setAttribute( "value2", it.value().second );
_this.appendChild( element );
}
for( objectVector::const_iterator it = m_objects.begin();
it != m_objects.end(); ++it )
{
@@ -593,6 +774,11 @@ void AutomationPattern::loadSettings( const QDomElement & _this )
m_timeMap[element.attribute( "pos" ).toInt()]
= LocaleHelper::toFloat(element.attribute("value"));
}
else if( element.tagName() == "ctrlpnt" )
{
m_controlPoints[element.attribute( "pos" ).toInt()] = {element.attribute( "value1" ).toInt(),
element.attribute( "value2" ).toFloat()};
}
else if( element.tagName() == "object" )
{
m_idsToResolve << element.attribute( "id" ).toInt();
@@ -616,6 +802,9 @@ void AutomationPattern::loadSettings( const QDomElement & _this )
changeLength( len );
}
generateTangents();
// Very important for reading older files
cleanControlPoints();
}
@@ -637,6 +826,62 @@ const QString AutomationPattern::name() const
void AutomationPattern::clampControlPoints(bool clampVertical)
{
timeMap::const_iterator it;
for (it = m_timeMap.begin(); it != m_timeMap.end(); it++)
{
int new_x = m_controlPoints[it.key()].first;
float new_y = m_controlPoints[it.key()].second;
// Clamp X positions
// If the control point x is less than its automation point
if ( it.key() > new_x )
{
new_x = it.key();
}
// The control point x must not pass the midpoints of its automation point and the automation points
// its left and right
else if ( it != m_timeMap.begin() && it.key() * 2 - new_x < ( (it-1).key() + it.key() ) / 2 )
{
new_x = it.key() * 2 - ( (it-1).key() + it.key() )/2;
}
else if ( it+1 != m_timeMap.end() && new_x > ( (it+1).key() + it.key() )/2 )
{
new_x = ( (it+1).key() + it.key() )/2;
}
if (clampVertical)
{
// Clamp y positions between the top and bottom of the screen
// Clamp the right control point (keep in mind the last control point isn't clamped)
if ( it+1 != m_timeMap.end() && new_y > getMax() )
{
new_y = getMax();
}
else if ( it+1 != m_timeMap.end() && new_y < getMin() )
{
new_y = getMin();
}
// Clamp the left control point (keep in mind the first control point isn't clamped)
if ( it != m_timeMap.begin() && 2 * it.value() - new_y > getMax() )
{
new_y = 2 * it.value() - getMax();
}
else if ( it != m_timeMap.begin() && 2 * it.value() - new_y < getMin() )
{
new_y = 2 * it.value() - getMin();
}
}
m_controlPoints.remove( it.key() );
m_controlPoints[it.key()] = {new_x, new_y};
}
}
TrackContentObjectView * AutomationPattern::createView( TrackView * _tv )
{
return new AutomationPatternView( this, _tv );
@@ -818,6 +1063,7 @@ void AutomationPattern::resolveAllIDs()
void AutomationPattern::clear()
{
m_timeMap.clear();
m_controlPoints.clear();
m_tangents.clear();
emit dataChanged();
@@ -870,6 +1116,40 @@ void AutomationPattern::cleanObjects()
void AutomationPattern::cleanControlPoints()
{
// If there's any control points that aren't connected to an automation point then destroy it
for( controlPointTimeMap::iterator it = m_controlPoints.begin(); it != m_controlPoints.end(); )
{
if(m_timeMap.contains( (int)it.key()) )
{
it++;
}
else
{
it = m_controlPoints.erase( it );
}
}
// If there's any automation points without a control point then insert control points
for( timeMap::iterator it = m_timeMap.begin(); it != m_timeMap.end(); )
{
if(m_controlPoints.contains( (int)it.key()) )
{
it++;
}
else
{
m_controlPoints[it.key()] = {it.key() + 50, it.value()};
}
}
clampControlPoints(false);
}
void AutomationPattern::generateTangents()
{
generateTangents(m_timeMap.begin(), m_timeMap.size());

View File

@@ -32,15 +32,15 @@
BBTrackContainer::BBTrackContainer() :
TrackContainer(),
m_bbComboBoxModel( this )
m_bbComboBoxModel(this)
{
connect( &m_bbComboBoxModel, SIGNAL( dataChanged() ),
this, SLOT( currentBBChanged() ) );
connect(&m_bbComboBoxModel, SIGNAL(dataChanged()),
this, SLOT(currentBBChanged()));
// we *always* want to receive updates even in case BB actually did
// not change upon setCurrentBB()-call
connect( &m_bbComboBoxModel, SIGNAL( dataUnchanged() ),
this, SLOT( currentBBChanged() ) );
setType( BBContainer );
connect(&m_bbComboBoxModel, SIGNAL(dataUnchanged()),
this, SLOT(currentBBChanged()));
setType(BBContainer);
}
@@ -53,27 +53,27 @@ BBTrackContainer::~BBTrackContainer()
bool BBTrackContainer::play( MidiTime _start, fpp_t _frames,
f_cnt_t _offset, int _tco_num )
bool BBTrackContainer::play(TimePos start, fpp_t frames, f_cnt_t offset, int tcoNum)
{
bool played_a_note = false;
if( lengthOfBB( _tco_num ) <= 0 )
bool notePlayed = false;
if (lengthOfBB(tcoNum) <= 0)
{
return false;
}
_start = _start % ( lengthOfBB( _tco_num ) * MidiTime::ticksPerBar() );
start = start % (lengthOfBB(tcoNum) * TimePos::ticksPerBar());
TrackList tl = tracks();
for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it )
for (Track * t : tl)
{
if( ( *it )->play( _start, _frames, _offset, _tco_num ) )
if (t->play(start, frames, offset, tcoNum))
{
played_a_note = true;
notePlayed = true;
}
}
return played_a_note;
return notePlayed;
}
@@ -81,7 +81,7 @@ bool BBTrackContainer::play( MidiTime _start, fpp_t _frames,
void BBTrackContainer::updateAfterTrackAdd()
{
if( numOfBBs() == 0 && !Engine::getSong()->isLoadingProject() )
if (numOfBBs() == 0 && !Engine::getSong()->isLoadingProject())
{
Engine::getSong()->addBBTrack();
}
@@ -90,21 +90,21 @@ void BBTrackContainer::updateAfterTrackAdd()
bar_t BBTrackContainer::lengthOfBB( int _bb ) const
bar_t BBTrackContainer::lengthOfBB(int bb) const
{
MidiTime max_length = MidiTime::ticksPerBar();
TimePos maxLength = TimePos::ticksPerBar();
const TrackList & tl = tracks();
for (Track* t : tl)
for (Track * t : tl)
{
// Don't create TCOs here if not exist
if (_bb < t->numOfTCOs())
// Don't create TCOs here if they don't exist
if (bb < t->numOfTCOs())
{
max_length = qMax(max_length, t->getTCO( _bb )->length());
maxLength = qMax(maxLength, t->getTCO(bb)->length());
}
}
return max_length.nextFullBar();
return maxLength.nextFullBar();
}
@@ -112,35 +112,35 @@ bar_t BBTrackContainer::lengthOfBB( int _bb ) const
int BBTrackContainer::numOfBBs() const
{
return Engine::getSong()->countTracks( Track::BBTrack );
return Engine::getSong()->countTracks(Track::BBTrack);
}
void BBTrackContainer::removeBB( int _bb )
void BBTrackContainer::removeBB(int bb)
{
TrackList tl = tracks();
for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it )
for (Track * t : tl)
{
delete ( *it )->getTCO( _bb );
( *it )->removeBar( _bb * DefaultTicksPerBar );
delete t->getTCO(bb);
t->removeBar(bb * DefaultTicksPerBar);
}
if( _bb <= currentBB() )
if (bb <= currentBB())
{
setCurrentBB( qMax( currentBB() - 1, 0 ) );
setCurrentBB(qMax(currentBB() - 1, 0));
}
}
void BBTrackContainer::swapBB( int _bb1, int _bb2 )
void BBTrackContainer::swapBB(int bb1, int bb2)
{
TrackList tl = tracks();
for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it )
for (Track * t : tl)
{
( *it )->swapPositionOfTCOs( _bb1, _bb2 );
t->swapPositionOfTCOs(bb1, bb2);
}
updateComboBox();
}
@@ -148,11 +148,10 @@ void BBTrackContainer::swapBB( int _bb1, int _bb2 )
void BBTrackContainer::updateBBTrack( TrackContentObject * _tco )
void BBTrackContainer::updateBBTrack(TrackContentObject * tco)
{
BBTrack * t = BBTrack::findBBTrack( _tco->startPosition() /
DefaultTicksPerBar );
if( t != NULL )
BBTrack * t = BBTrack::findBBTrack(tco->startPosition() / DefaultTicksPerBar);
if (t != NULL)
{
t->dataChanged();
}
@@ -164,11 +163,11 @@ void BBTrackContainer::updateBBTrack( TrackContentObject * _tco )
void BBTrackContainer::fixIncorrectPositions()
{
TrackList tl = tracks();
for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it )
for (Track * t : tl)
{
for( int i = 0; i < numOfBBs(); ++i )
for (int i = 0; i < numOfBBs(); ++i)
{
( *it )->getTCO( i )->movePosition( MidiTime( i, 0 ) );
t->getTCO(i)->movePosition(TimePos(i, 0));
}
}
}
@@ -178,7 +177,7 @@ void BBTrackContainer::fixIncorrectPositions()
void BBTrackContainer::play()
{
if( Engine::getSong()->playMode() != Song::Mode_PlayBB )
if (Engine::getSong()->playMode() != Song::Mode_PlayBB)
{
Engine::getSong()->playBB();
}
@@ -201,16 +200,16 @@ void BBTrackContainer::stop()
void BBTrackContainer::updateComboBox()
{
const int cur_bb = currentBB();
const int curBB = currentBB();
m_bbComboBoxModel.clear();
for( int i = 0; i < numOfBBs(); ++i )
for (int i = 0; i < numOfBBs(); ++i)
{
BBTrack * bbt = BBTrack::findBBTrack( i );
m_bbComboBoxModel.addItem( bbt->name() );
BBTrack * bbt = BBTrack::findBBTrack(i);
m_bbComboBoxModel.addItem(bbt->name());
}
setCurrentBB( cur_bb );
setCurrentBB(curBB);
}
@@ -218,14 +217,13 @@ void BBTrackContainer::updateComboBox()
void BBTrackContainer::currentBBChanged()
{
// now update all track-labels (the current one has to become white,
// the others gray)
// now update all track-labels (the current one has to become white, the others gray)
TrackList tl = Engine::getSong()->tracks();
for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it )
for (Track * t : tl)
{
if( ( *it )->type() == Track::BBTrack )
if (t->type() == Track::BBTrack)
{
( *it )->dataChanged();
t->dataChanged();
}
}
}
@@ -233,27 +231,27 @@ void BBTrackContainer::currentBBChanged()
void BBTrackContainer::createTCOsForBB( int _bb )
void BBTrackContainer::createTCOsForBB(int bb)
{
TrackList tl = tracks();
for( int i = 0; i < tl.size(); ++i )
for (Track * t : tl)
{
tl[i]->createTCOsForBB( _bb );
t->createTCOsForBB(bb);
}
}
AutomatedValueMap BBTrackContainer::automatedValuesAt(MidiTime time, int tcoNum) const
AutomatedValueMap BBTrackContainer::automatedValuesAt(TimePos time, int tcoNum) const
{
Q_ASSERT(tcoNum >= 0);
Q_ASSERT(time.getTicks() >= 0);
auto length_bars = lengthOfBB(tcoNum);
auto length_ticks = length_bars * MidiTime::ticksPerBar();
if (time > length_ticks)
auto lengthBars = lengthOfBB(tcoNum);
auto lengthTicks = lengthBars * TimePos::ticksPerBar();
if (time > lengthTicks)
{
time = length_ticks;
time = lengthTicks;
}
return TrackContainer::automatedValuesAt(time + (MidiTime::ticksPerBar() * tcoNum), tcoNum);
return TrackContainer::automatedValuesAt(time + (TimePos::ticksPerBar() * tcoNum), tcoNum);
}

View File

@@ -67,9 +67,11 @@ set(LMMS_SRCS
core/SerializingObject.cpp
core/Song.cpp
core/TempoSyncKnobModel.cpp
core/TimePos.cpp
core/ToolPlugin.cpp
core/Track.cpp
core/TrackContainer.cpp
core/TrackContentObject.cpp
core/ValueBuffer.cpp
core/VstSyncController.cpp
core/StepRecorder.cpp
@@ -98,6 +100,7 @@ set(LMMS_SRCS
core/lv2/Lv2Ports.cpp
core/lv2/Lv2Proc.cpp
core/lv2/Lv2Manager.cpp
core/lv2/Lv2Options.cpp
core/lv2/Lv2SubPluginFeatures.cpp
core/lv2/Lv2UridCache.cpp
core/lv2/Lv2UridMap.cpp
@@ -112,7 +115,6 @@ set(LMMS_SRCS
core/midi/MidiSndio.cpp
core/midi/MidiApple.cpp
core/midi/MidiPort.cpp
core/midi/MidiTime.cpp
core/midi/MidiWinMM.cpp
PARENT_SCOPE

View File

@@ -528,17 +528,16 @@ void ConfigManager::loadConfigFile(const QString & configFile)
{
#if defined(LMMS_BUILD_WIN32)
m_stkDir = m_dataDir + "stk/rawwaves/";
#elif defined(LMMS_BUILD_APPLE)
m_stkDir = qApp->applicationDirPath() + "/../share/stk/rawwaves/";
#else
if ( qApp->applicationDirPath().startsWith("/tmp/") )
// Look for bundled raw waves first
m_stkDir = qApp->applicationDirPath() + "/../share/stk/rawwaves/";
// Try system installations if not exists
if (!QDir(m_stkDir).exists())
{
// Assume AppImage bundle
m_stkDir = qApp->applicationDirPath() + "/../share/stk/rawwaves/";
m_stkDir = "/usr/local/share/stk/rawwaves/";
}
else
if (!QDir(m_stkDir).exists())
{
// Fallback to system provided location
m_stkDir = "/usr/share/stk/rawwaves/";
}
#endif

View File

@@ -47,7 +47,6 @@ Lv2Manager * LmmsCore::s_lv2Manager = nullptr;
#endif
Ladspa2LMMS * LmmsCore::s_ladspaManager = NULL;
void* LmmsCore::s_dndPluginKey = nullptr;
DummyTrackContainer * LmmsCore::s_dummyTC = NULL;
@@ -79,7 +78,6 @@ void LmmsCore::init( bool renderOnly )
s_mixer->initDevices();
PresetPreviewPlayHandle::init();
s_dummyTC = new DummyTrackContainer;
emit engine->initProgress(tr("Launching mixer threads"));
s_mixer->startProcessing();
@@ -98,7 +96,6 @@ void LmmsCore::destroy()
s_song->clearProject();
deleteHelper( &s_bbTrackContainer );
deleteHelper( &s_dummyTC );
deleteHelper( &s_fxMixer );
deleteHelper( &s_mixer );
@@ -116,6 +113,18 @@ void LmmsCore::destroy()
delete ConfigManager::inst();
}
bool LmmsCore::ignorePluginBlacklist()
{
const char* envVar = getenv("LMMS_IGNORE_BLACKLIST");
return (envVar && *envVar);
}
float LmmsCore::framesPerTick(sample_rate_t sampleRate)
{
return sampleRate * 60.0f * 4 /

View File

@@ -506,7 +506,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
NotePlayHandleManager::acquire( _n->instrumentTrack(),
frames_processed,
gated_frames,
Note( MidiTime( 0 ), MidiTime( 0 ), sub_note_key, _n->getVolume(),
Note( TimePos( 0 ), TimePos( 0 ), sub_note_key, _n->getVolume(),
_n->getPanning(), _n->detuning() ),
_n, -1, NotePlayHandle::OriginArpeggio )
);

View File

@@ -361,7 +361,7 @@ const surroundSampleFrame * Mixer::renderNextBuffer()
// Stop crash with metronome if empty project
Engine::getSong()->countTracks() )
{
tick_t ticksPerBar = MidiTime::ticksPerBar();
tick_t ticksPerBar = TimePos::ticksPerBar();
if ( p.getTicks() % ( ticksPerBar / 1 ) == 0 )
{
addPlayHandle( new SamplePlayHandle( "misc/metronome02.ogg" ) );
@@ -600,21 +600,6 @@ void Mixer::doSetAudioDevice( AudioDevice * _dev )
void Mixer::setAudioDevice( AudioDevice * _dev,
bool startNow )
{
stopProcessing();
doSetAudioDevice( _dev );
emit sampleRateChanged();
if (startNow) {startProcessing();}
}
void Mixer::setAudioDevice(AudioDevice * _dev,
const struct qualitySettings & _qs,
bool _needs_fifo,

View File

@@ -31,7 +31,7 @@
#include "DetuningHelper.h"
Note::Note( const MidiTime & length, const MidiTime & pos,
Note::Note( const TimePos & length, const TimePos & pos,
int key, volume_t volume, panning_t panning,
DetuningHelper * detuning ) :
m_selected( false ),
@@ -93,7 +93,7 @@ Note::~Note()
void Note::setLength( const MidiTime & length )
void Note::setLength( const TimePos & length )
{
m_length = length;
}
@@ -101,7 +101,7 @@ void Note::setLength( const MidiTime & length )
void Note::setPos( const MidiTime & pos )
void Note::setPos( const TimePos & pos )
{
m_pos = pos;
}
@@ -136,7 +136,7 @@ void Note::setPanning( panning_t panning )
MidiTime Note::quantized( const MidiTime & m, const int qGrid )
TimePos Note::quantized( const TimePos & m, const int qGrid )
{
float p = ( (float) m / qGrid );
if( p - floorf( p ) < 0.5f )

View File

@@ -211,7 +211,7 @@ void NotePlayHandle::play( sampleFrame * _working_buffer )
// send MidiNoteOn event
m_instrumentTrack->processOutEvent(
MidiEvent( MidiNoteOn, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ),
MidiTime::fromFrames( offset(), Engine::framesPerTick() ),
TimePos::fromFrames( offset(), Engine::framesPerTick() ),
offset() );
}
@@ -374,7 +374,7 @@ void NotePlayHandle::noteOff( const f_cnt_t _s )
// send MidiNoteOff event
m_instrumentTrack->processOutEvent(
MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ),
MidiTime::fromFrames( _s, Engine::framesPerTick() ),
TimePos::fromFrames( _s, Engine::framesPerTick() ),
_s );
}
@@ -383,7 +383,7 @@ void NotePlayHandle::noteOff( const f_cnt_t _s )
{
if( m_origin == OriginMidiInput )
{
setLength( MidiTime( static_cast<f_cnt_t>( totalFramesPlayed() / Engine::framesPerTick() ) ) );
setLength( TimePos( static_cast<f_cnt_t>( totalFramesPlayed() / Engine::framesPerTick() ) ) );
m_instrumentTrack->midiNoteOff( *this );
}
}
@@ -519,7 +519,7 @@ void NotePlayHandle::updateFrequency()
void NotePlayHandle::processMidiTime( const MidiTime& time )
void NotePlayHandle::processTimePos( const TimePos& time )
{
if( detuning() && time >= songGlobalParentOffset()+pos() )
{
@@ -623,3 +623,8 @@ void NotePlayHandleManager::extend( int c )
++n;
}
}
void NotePlayHandleManager::free()
{
MM_FREE(s_available);
}

View File

@@ -50,10 +50,22 @@ const char *PluginIssue::msgFor(const PluginIssueType &it)
return "port is missing min value";
case portHasNoMax:
return "port is missing max value";
case minGreaterMax:
return "port minimum is greater than maximum";
case defaultValueNotInRange:
return "default value is not in range [min, max]";
case logScaleMinMissing:
return "logscale requires minimum value";
case logScaleMaxMissing:
return "logscale requires maximum value";
case logScaleMinMaxDifferentSigns:
return "logscale with min < 0 < max";
case featureNotSupported:
return "required feature not supported";
case badPortType:
return "unsupported port type";
case blacklisted:
return "blacklisted plugin";
case noIssue:
return nullptr;
}
@@ -63,6 +75,24 @@ const char *PluginIssue::msgFor(const PluginIssueType &it)
bool PluginIssue::operator==(const PluginIssue &other) const
{
return (m_issueType == other.m_issueType) && (m_info == other.m_info);
}
bool PluginIssue::operator<(const PluginIssue &other) const
{
return (m_issueType != other.m_issueType)
? m_issueType < other.m_issueType
: m_info < other.m_info;
}
QDebug operator<<(QDebug stream, const PluginIssue &iss)
{
stream << PluginIssue::msgFor(iss.m_issueType);

File diff suppressed because it is too large Load Diff

View File

@@ -73,7 +73,7 @@ void SampleRecordHandle::play( sampleFrame * /*_working_buffer*/ )
writeBuffer( recbuf, frames );
m_framesRecorded += frames;
MidiTime len = (tick_t)( m_framesRecorded / Engine::framesPerTick() );
TimePos len = (tick_t)( m_framesRecorded / Engine::framesPerTick() );
if( len > m_minLength )
{
// m_tco->changeLength( len );

View File

@@ -30,6 +30,8 @@
#include <QFileInfo>
#include <QMessageBox>
#include <algorithm>
#include <cmath>
#include <functional>
#include "AutomationTrack.h"
@@ -46,6 +48,8 @@
#include "FxMixerView.h"
#include "GuiApplication.h"
#include "ExportFilter.h"
#include "InstrumentTrack.h"
#include "NotePlayHandle.h"
#include "Pattern.h"
#include "PianoRoll.h"
#include "ProjectJournal.h"
@@ -55,7 +59,7 @@
#include "PeakController.h"
tick_t MidiTime::s_ticksPerBar = DefaultTicksPerBar;
tick_t TimePos::s_ticksPerBar = DefaultTicksPerBar;
@@ -164,7 +168,7 @@ void Song::setTempo()
void Song::setTimeSignature()
{
MidiTime::setTicksPerBar( ticksPerBar() );
TimePos::setTicksPerBar( ticksPerBar() );
emit timeSignatureChanged( m_oldTicksPerBar, ticksPerBar() );
emit dataChanged();
m_oldTicksPerBar = ticksPerBar();
@@ -191,231 +195,164 @@ void Song::savePos()
void Song::processNextBuffer()
{
m_vstSyncController.setPlaybackJumped( false );
m_vstSyncController.setPlaybackJumped(false);
// if not playing, nothing to do
if( m_playing == false )
// If nothing is playing, there is nothing to do
if (!m_playing) { return; }
// At the beginning of the song, we have to reset the LFOs
if (m_playMode == Mode_PlaySong && getPlayPos() == 0)
{
return;
EnvelopeAndLfoParameters::instances()->reset();
}
TrackList trackList;
int tcoNum = -1; // track content object number
int clipNum = -1; // The number of the clip that will be played
// determine the list of tracks to play and the track content object
// (TCO) number
switch( m_playMode )
// Determine the list of tracks to play and the clip number
switch (m_playMode)
{
case Mode_PlaySong:
trackList = tracks();
// at song-start we have to reset the LFOs
if( m_playPos[Mode_PlaySong] == 0 )
{
EnvelopeAndLfoParameters::instances()->reset();
}
break;
case Mode_PlayBB:
if( Engine::getBBTrackContainer()->numOfBBs() > 0 )
if (Engine::getBBTrackContainer()->numOfBBs() > 0)
{
tcoNum = Engine::getBBTrackContainer()->
currentBB();
trackList.push_back( BBTrack::findBBTrack(
tcoNum ) );
clipNum = Engine::getBBTrackContainer()->currentBB();
trackList.push_back(BBTrack::findBBTrack(clipNum));
}
break;
case Mode_PlayPattern:
if( m_patternToPlay != NULL )
if (m_patternToPlay)
{
tcoNum = m_patternToPlay->getTrack()->
getTCONum( m_patternToPlay );
trackList.push_back(
m_patternToPlay->getTrack() );
clipNum = m_patternToPlay->getTrack()->getTCONum(m_patternToPlay);
trackList.push_back(m_patternToPlay->getTrack());
}
break;
default:
return;
}
// if we have no tracks to play, nothing to do
if( trackList.empty() == true )
{
return;
}
// If we have no tracks to play, there is nothing to do
if (trackList.empty()) { return; }
// check for looping-mode and act if necessary
TimeLineWidget * tl = m_playPos[m_playMode].m_timeLine;
bool checkLoop =
tl != NULL && m_exporting == false && tl->loopPointsEnabled();
if( checkLoop )
// If the playback position is outside of the range [begin, end), move it to
// begin and inform interested parties.
// Returns true if the playback position was moved, else false.
const auto enforceLoop = [this](const TimePos& begin, const TimePos& end)
{
// if looping-mode is enabled and we are outside of the looping
// range, go to the beginning of the range
if( m_playPos[m_playMode] < tl->loopBegin() ||
m_playPos[m_playMode] >= tl->loopEnd() )
if (getPlayPos() < begin || getPlayPos() >= end)
{
setToTime(tl->loopBegin());
m_playPos[m_playMode].setTicks(
tl->loopBegin().getTicks() );
m_vstSyncController.setPlaybackJumped( true );
setToTime(begin);
m_vstSyncController.setPlaybackJumped(true);
emit updateSampleTracks();
return true;
}
return false;
};
const auto timeline = getPlayPos().m_timeLine;
const auto loopEnabled = !m_exporting && timeline && timeline->loopPointsEnabled();
// Ensure playback begins within the loop if it is enabled
if (loopEnabled) { enforceLoop(timeline->loopBegin(), timeline->loopEnd()); }
// Inform VST plugins if the user moved the play head
if (getPlayPos().jumped())
{
m_vstSyncController.setPlaybackJumped(true);
getPlayPos().setJumped(false);
}
if( m_playPos[m_playMode].jumped() )
const auto framesPerTick = Engine::framesPerTick();
const auto framesPerPeriod = Engine::mixer()->framesPerPeriod();
f_cnt_t frameOffsetInPeriod = 0;
while (frameOffsetInPeriod < framesPerPeriod)
{
m_vstSyncController.setPlaybackJumped( true );
m_playPos[m_playMode].setJumped( false );
}
auto frameOffsetInTick = getPlayPos().currentFrame();
f_cnt_t framesPlayed = 0;
const float framesPerTick = Engine::framesPerTick();
while( framesPlayed < Engine::mixer()->framesPerPeriod() )
{
m_vstSyncController.update();
float currentFrame = m_playPos[m_playMode].currentFrame();
// did we play a tick?
if( currentFrame >= framesPerTick )
// If a whole tick has elapsed, update the frame and tick count, and check any loops
if (frameOffsetInTick >= framesPerTick)
{
int ticks = m_playPos[m_playMode].getTicks() +
( int )( currentFrame / framesPerTick );
// Transfer any whole ticks from the frame count to the tick count
const auto elapsedTicks = static_cast<int>(frameOffsetInTick / framesPerTick);
getPlayPos().setTicks(getPlayPos().getTicks() + elapsedTicks);
frameOffsetInTick -= elapsedTicks * framesPerTick;
getPlayPos().setCurrentFrame(frameOffsetInTick);
// did we play a whole bar?
if( ticks >= MidiTime::ticksPerBar() )
// If we are playing a BB track, or a pattern with no loop enabled,
// loop back to the beginning when we reach the end
if (m_playMode == Mode_PlayBB)
{
// per default we just continue playing even if
// there's no more stuff to play
// (song-play-mode)
int maxBar = m_playPos[m_playMode].getBar()
+ 2;
// then decide whether to go over to next bar
// or to loop back to first bar
if( m_playMode == Mode_PlayBB )
{
maxBar = Engine::getBBTrackContainer()
->lengthOfCurrentBB();
}
else if( m_playMode == Mode_PlayPattern &&
m_loopPattern == true &&
tl != NULL &&
tl->loopPointsEnabled() == false )
{
maxBar = m_patternToPlay->length()
.getBar();
}
// end of played object reached?
if( m_playPos[m_playMode].getBar() + 1
>= maxBar )
{
// then start from beginning and keep
// offset
ticks %= ( maxBar * MidiTime::ticksPerBar() );
// wrap milli second counter
setToTimeByTicks(ticks);
m_vstSyncController.setPlaybackJumped( true );
}
enforceLoop(TimePos{0}, TimePos{Engine::getBBTrackContainer()->lengthOfCurrentBB(), 0});
}
else if (m_playMode == Mode_PlayPattern && m_loopPattern && !loopEnabled)
{
enforceLoop(TimePos{0}, m_patternToPlay->length());
}
m_playPos[m_playMode].setTicks( ticks );
if (checkLoop || m_loopRenderRemaining > 1)
// Handle loop points, and inform VST plugins of the loop status
if (loopEnabled || (m_loopRenderRemaining > 1 && getPlayPos() >= timeline->loopBegin()))
{
m_vstSyncController.startCycle(
tl->loopBegin().getTicks(), tl->loopEnd().getTicks() );
timeline->loopBegin().getTicks(), timeline->loopEnd().getTicks());
// if looping-mode is enabled and we have got
// past the looping range, return to the
// beginning of the range
if( m_playPos[m_playMode] >= tl->loopEnd() )
// Loop if necessary, and decrement the remaining loops if we did
if (enforceLoop(timeline->loopBegin(), timeline->loopEnd())
&& m_loopRenderRemaining > 1)
{
if (m_loopRenderRemaining > 1)
m_loopRenderRemaining--;
ticks = tl->loopBegin().getTicks();
m_playPos[m_playMode].setTicks( ticks );
setToTime(tl->loopBegin());
m_vstSyncController.setPlaybackJumped( true );
emit updateSampleTracks();
m_loopRenderRemaining--;
}
}
else
{
m_vstSyncController.stopCycle();
}
currentFrame = fmodf( currentFrame, framesPerTick );
m_playPos[m_playMode].setCurrentFrame( currentFrame );
}
if( framesPlayed == 0 )
const f_cnt_t framesUntilNextPeriod = framesPerPeriod - frameOffsetInPeriod;
const f_cnt_t framesUntilNextTick = static_cast<f_cnt_t>(std::ceil(framesPerTick - frameOffsetInTick));
// We want to proceed to the next buffer or tick, whichever is closer
const auto framesToPlay = std::min(framesUntilNextPeriod, framesUntilNextTick);
if (frameOffsetInPeriod == 0)
{
// update VST sync position after we've corrected frame/
// tick count but before actually playing any frames
m_vstSyncController.setAbsolutePosition(
m_playPos[m_playMode].getTicks()
+ m_playPos[m_playMode].currentFrame()
/ (double) framesPerTick );
// First frame of buffer: update VST sync position.
// This must be done after we've corrected the frame/tick count,
// but before actually playing any frames.
m_vstSyncController.setAbsolutePosition(getPlayPos().getTicks()
+ getPlayPos().currentFrame() / static_cast<double>(framesPerTick));
m_vstSyncController.update();
}
f_cnt_t framesToPlay =
Engine::mixer()->framesPerPeriod() - framesPlayed;
f_cnt_t framesLeft = ( f_cnt_t )framesPerTick -
( f_cnt_t )currentFrame;
// skip last frame fraction
if( framesLeft == 0 )
if (static_cast<f_cnt_t>(frameOffsetInTick) == 0)
{
++framesPlayed;
m_playPos[m_playMode].setCurrentFrame( currentFrame
+ 1.0f );
continue;
}
// do we have samples left in this tick but these are less
// than samples we have to play?
if( framesLeft < framesToPlay )
{
// then set framesToPlay to remaining samples, the
// rest will be played in next loop
framesToPlay = framesLeft;
}
if( ( f_cnt_t ) currentFrame == 0 )
{
processAutomations(trackList, m_playPos[m_playMode], framesToPlay);
// loop through all tracks and play them
for( int i = 0; i < trackList.size(); ++i )
// First frame of tick: process automation and play tracks
processAutomations(trackList, getPlayPos(), framesToPlay);
for (const auto track : trackList)
{
trackList[i]->play( m_playPos[m_playMode],
framesToPlay,
framesPlayed, tcoNum );
track->play(getPlayPos(), framesToPlay, frameOffsetInPeriod, clipNum);
}
}
// update frame-counters
framesPlayed += framesToPlay;
m_playPos[m_playMode].setCurrentFrame( framesToPlay +
currentFrame );
m_elapsedMilliSeconds[m_playMode] += MidiTime::ticksToMilliseconds(framesToPlay / framesPerTick, getTempo());
// Update frame counters
frameOffsetInPeriod += framesToPlay;
frameOffsetInTick += framesToPlay;
getPlayPos().setCurrentFrame(frameOffsetInTick);
m_elapsedMilliSeconds[m_playMode] += TimePos::ticksToMilliseconds(framesToPlay / framesPerTick, getTempo());
m_elapsedBars = m_playPos[Mode_PlaySong].getBar();
m_elapsedTicks = ( m_playPos[Mode_PlaySong].getTicks() % ticksPerBar() ) / 48;
m_elapsedTicks = (m_playPos[Mode_PlaySong].getTicks() % ticksPerBar()) / 48;
}
}
void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fpp_t)
void Song::processAutomations(const TrackList &tracklist, TimePos timeStart, fpp_t)
{
AutomatedValueMap values;
@@ -457,7 +394,7 @@ void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fp
for (TrackContentObject* tco : tcos)
{
auto p = dynamic_cast<AutomationPattern *>(tco);
MidiTime relTime = timeStart - p->startPosition();
TimePos relTime = timeStart - p->startPosition();
if (p->isRecording() && relTime >= 0 && relTime < p->length())
{
const AutomatableModel* recordedModel = p->firstObject();
@@ -493,7 +430,7 @@ bool Song::isExportDone() const
int Song::getExportProgress() const
{
MidiTime pos = m_playPos[m_playMode];
TimePos pos = m_playPos[m_playMode];
if (pos >= m_exportSongEnd)
{
@@ -637,7 +574,7 @@ void Song::setPlayPos( tick_t ticks, PlayModes playMode )
{
tick_t ticksFromPlayMode = m_playPos[playMode].getTicks();
m_elapsedTicks += ticksFromPlayMode - ticks;
m_elapsedMilliSeconds[playMode] += MidiTime::ticksToMilliseconds( ticks - ticksFromPlayMode, getTempo() );
m_elapsedMilliSeconds[playMode] += TimePos::ticksToMilliseconds( ticks - ticksFromPlayMode, getTempo() );
m_playPos[playMode].setTicks( ticks );
m_playPos[playMode].setCurrentFrame( 0.0f );
m_playPos[playMode].setJumped( true );
@@ -755,7 +692,7 @@ void Song::startExport()
}
else
{
m_exportSongEnd = MidiTime(m_length, 0);
m_exportSongEnd = TimePos(m_length, 0);
// Handle potentially ridiculous loop points gracefully.
if (m_loopRenderCount > 1 && m_playPos[Mode_PlaySong].m_timeLine->loopEnd() > m_exportSongEnd)
@@ -764,18 +701,18 @@ void Song::startExport()
}
if (!m_exportLoop)
m_exportSongEnd += MidiTime(1,0);
m_exportSongEnd += TimePos(1,0);
m_exportSongBegin = MidiTime(0,0);
m_exportSongBegin = TimePos(0,0);
// FIXME: remove this check once we load timeline in headless mode
if (m_playPos[Mode_PlaySong].m_timeLine)
{
m_exportLoopBegin = m_playPos[Mode_PlaySong].m_timeLine->loopBegin() < m_exportSongEnd &&
m_playPos[Mode_PlaySong].m_timeLine->loopEnd() <= m_exportSongEnd ?
m_playPos[Mode_PlaySong].m_timeLine->loopBegin() : MidiTime(0,0);
m_playPos[Mode_PlaySong].m_timeLine->loopBegin() : TimePos(0,0);
m_exportLoopEnd = m_playPos[Mode_PlaySong].m_timeLine->loopBegin() < m_exportSongEnd &&
m_playPos[Mode_PlaySong].m_timeLine->loopEnd() <= m_exportSongEnd ?
m_playPos[Mode_PlaySong].m_timeLine->loopEnd() : MidiTime(0,0);
m_playPos[Mode_PlaySong].m_timeLine->loopEnd() : TimePos(0,0);
}
m_playPos[Mode_PlaySong].setTicks( 0 );
@@ -871,7 +808,7 @@ AutomationPattern * Song::tempoAutomationPattern()
}
AutomatedValueMap Song::automatedValuesAt(MidiTime time, int tcoNum) const
AutomatedValueMap Song::automatedValuesAt(TimePos time, int tcoNum) const
{
return TrackContainer::automatedValuesFromTracks(TrackList{m_globalAutomationTrack} << tracks(), time, tcoNum);
}
@@ -949,8 +886,6 @@ void Song::clearProject()
Engine::projectJournal()->clearJournal();
Engine::projectJournal()->setJournalling( true );
InstrumentTrackView::cleanupWindowCache();
}

View File

@@ -43,7 +43,7 @@ void StepRecorder::initialize()
connect(&m_updateReleasedTimer, SIGNAL(timeout()), this, SLOT(removeNotesReleasedForTooLong()));
}
void StepRecorder::start(const MidiTime& currentPosition, const MidiTime& stepLength)
void StepRecorder::start(const TimePos& currentPosition, const TimePos& stepLength)
{
m_isRecording = true;
@@ -53,7 +53,7 @@ void StepRecorder::start(const MidiTime& currentPosition, const MidiTime& stepLe
const int q = m_pianoRoll.quantization();
const int curPosTicks = currentPosition.getTicks();
const int QuantizedPosTicks = (curPosTicks / q) * q;
const MidiTime& QuantizedPos = MidiTime(QuantizedPosTicks);
const TimePos& QuantizedPos = TimePos(QuantizedPosTicks);
m_curStepStartPos = QuantizedPos;
m_curStepLength = 0;
@@ -154,7 +154,7 @@ bool StepRecorder::keyPressEvent(QKeyEvent* ke)
return event_handled;
}
void StepRecorder::setStepsLength(const MidiTime& newLength)
void StepRecorder::setStepsLength(const TimePos& newLength)
{
if(m_isStepInProgress)
{
@@ -319,7 +319,7 @@ void StepRecorder::removeNotesReleasedForTooLong()
}
}
MidiTime StepRecorder::getCurStepEndPos()
TimePos StepRecorder::getCurStepEndPos()
{
return m_curStepStartPos + m_curStepLength;
}

View File

@@ -1,5 +1,5 @@
/*
* MidiTime.cpp - Class that encapsulates the position of a note/event in terms of
* TimePos.cpp - Class that encapsulates the position of a note/event in terms of
* its bar, beat and tick.
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net
@@ -23,7 +23,7 @@
*
*/
#include "MidiTime.h"
#include "TimePos.h"
#include "MeterModel.h"
@@ -53,17 +53,17 @@ int TimeSig::denominator() const
MidiTime::MidiTime( const bar_t bar, const tick_t ticks ) :
TimePos::TimePos( const bar_t bar, const tick_t ticks ) :
m_ticks( bar * s_ticksPerBar + ticks )
{
}
MidiTime::MidiTime( const tick_t ticks ) :
TimePos::TimePos( const tick_t ticks ) :
m_ticks( ticks )
{
}
MidiTime MidiTime::quantize(float bars) const
TimePos TimePos::quantize(float bars) const
{
//The intervals we should snap to, our new position should be a factor of this
int interval = s_ticksPerBar * bars;
@@ -78,80 +78,80 @@ MidiTime MidiTime::quantize(float bars) const
}
MidiTime MidiTime::toAbsoluteBar() const
TimePos TimePos::toAbsoluteBar() const
{
return getBar() * s_ticksPerBar;
}
MidiTime& MidiTime::operator+=( const MidiTime& time )
TimePos& TimePos::operator+=( const TimePos& time )
{
m_ticks += time.m_ticks;
return *this;
}
MidiTime& MidiTime::operator-=( const MidiTime& time )
TimePos& TimePos::operator-=( const TimePos& time )
{
m_ticks -= time.m_ticks;
return *this;
}
bar_t MidiTime::getBar() const
bar_t TimePos::getBar() const
{
return m_ticks / s_ticksPerBar;
}
bar_t MidiTime::nextFullBar() const
bar_t TimePos::nextFullBar() const
{
return ( m_ticks + ( s_ticksPerBar - 1 ) ) / s_ticksPerBar;
}
void MidiTime::setTicks( tick_t ticks )
void TimePos::setTicks( tick_t ticks )
{
m_ticks = ticks;
}
tick_t MidiTime::getTicks() const
tick_t TimePos::getTicks() const
{
return m_ticks;
}
MidiTime::operator int() const
TimePos::operator int() const
{
return m_ticks;
}
tick_t MidiTime::ticksPerBeat( const TimeSig &sig ) const
tick_t TimePos::ticksPerBeat( const TimeSig &sig ) const
{
// (number of ticks per bar) divided by (number of beats per bar)
return ticksPerBar(sig) / sig.numerator();
}
tick_t MidiTime::getTickWithinBar( const TimeSig &sig ) const
tick_t TimePos::getTickWithinBar( const TimeSig &sig ) const
{
return m_ticks % ticksPerBar( sig );
}
tick_t MidiTime::getBeatWithinBar( const TimeSig &sig ) const
tick_t TimePos::getBeatWithinBar( const TimeSig &sig ) const
{
return getTickWithinBar( sig ) / ticksPerBeat( sig );
}
tick_t MidiTime::getTickWithinBeat( const TimeSig &sig ) const
tick_t TimePos::getTickWithinBeat( const TimeSig &sig ) const
{
return getTickWithinBar( sig ) % ticksPerBeat( sig );
}
f_cnt_t MidiTime::frames( const float framesPerTick ) const
f_cnt_t TimePos::frames( const float framesPerTick ) const
{
if( m_ticks >= 0 )
{
@@ -160,53 +160,53 @@ f_cnt_t MidiTime::frames( const float framesPerTick ) const
return 0;
}
double MidiTime::getTimeInMilliseconds( bpm_t beatsPerMinute ) const
double TimePos::getTimeInMilliseconds( bpm_t beatsPerMinute ) const
{
return ticksToMilliseconds( getTicks(), beatsPerMinute );
}
MidiTime MidiTime::fromFrames( const f_cnt_t frames, const float framesPerTick )
TimePos TimePos::fromFrames( const f_cnt_t frames, const float framesPerTick )
{
return MidiTime( static_cast<int>( frames / framesPerTick ) );
return TimePos( static_cast<int>( frames / framesPerTick ) );
}
tick_t MidiTime::ticksPerBar()
tick_t TimePos::ticksPerBar()
{
return s_ticksPerBar;
}
tick_t MidiTime::ticksPerBar( const TimeSig &sig )
tick_t TimePos::ticksPerBar( const TimeSig &sig )
{
return DefaultTicksPerBar * sig.numerator() / sig.denominator();
}
int MidiTime::stepsPerBar()
int TimePos::stepsPerBar()
{
int steps = ticksPerBar() / DefaultBeatsPerBar;
return qMax( 1, steps );
}
void MidiTime::setTicksPerBar( tick_t tpb )
void TimePos::setTicksPerBar( tick_t tpb )
{
s_ticksPerBar = tpb;
}
MidiTime MidiTime::stepPosition( int step )
TimePos TimePos::stepPosition( int step )
{
return step * ticksPerBar() / stepsPerBar();
}
double MidiTime::ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute )
double TimePos::ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute )
{
return MidiTime::ticksToMilliseconds( static_cast<double>(ticks), beatsPerMinute );
return TimePos::ticksToMilliseconds( static_cast<double>(ticks), beatsPerMinute );
}
double MidiTime::ticksToMilliseconds(double ticks, bpm_t beatsPerMinute)
double TimePos::ticksToMilliseconds(double ticks, bpm_t beatsPerMinute)
{
// 60 * 1000 / 48 = 1250
return ( ticks * 1250 ) / beatsPerMinute;

File diff suppressed because it is too large Load Diff

View File

@@ -248,13 +248,13 @@ bool TrackContainer::isEmpty() const
AutomatedValueMap TrackContainer::automatedValuesAt(MidiTime time, int tcoNum) const
AutomatedValueMap TrackContainer::automatedValuesAt(TimePos time, int tcoNum) const
{
return automatedValuesFromTracks(tracks(), time, tcoNum);
}
AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tracks, MidiTime time, int tcoNum)
AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tracks, TimePos time, int tcoNum)
{
Track::tcoVector tcos;
@@ -295,7 +295,7 @@ AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tra
if (! p->hasAutomation()) {
continue;
}
MidiTime relTime = time - p->startPosition();
TimePos relTime = time - p->startPosition();
if (! p->getAutoResize()) {
relTime = qMin(relTime, p->length());
}
@@ -311,9 +311,9 @@ AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tra
auto bbIndex = dynamic_cast<class BBTrack*>(bb->getTrack())->index();
auto bbContainer = Engine::getBBTrackContainer();
MidiTime bbTime = time - tco->startPosition();
TimePos bbTime = time - tco->startPosition();
bbTime = std::min(bbTime, tco->length());
bbTime = bbTime % (bbContainer->lengthOfBB(bbIndex) * MidiTime::ticksPerBar());
bbTime = bbTime % (bbContainer->lengthOfBB(bbIndex) * TimePos::ticksPerBar());
auto bbValues = bbContainer->automatedValuesAt(bbTime, bbIndex);
for (auto it=bbValues.begin(); it != bbValues.end(); it++)
@@ -331,16 +331,3 @@ AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tra
return valueMap;
};
DummyTrackContainer::DummyTrackContainer() :
TrackContainer(),
m_dummyInstrumentTrack( NULL )
{
setJournalling( false );
m_dummyInstrumentTrack = dynamic_cast<InstrumentTrack *>(
Track::create( Track::InstrumentTrack,
this ) );
m_dummyInstrumentTrack->setJournalling( false );
}

Some files were not shown because too many files have changed in this diff Show More