Merge remote-tracking branch 'origin/stable-0.4-new-fx-mixer'
Conflicts: include/PlayHandle.h src/core/FxMixer.cpp src/core/Mixer.cpp src/gui/FxMixerView.cpp src/tracks/InstrumentTrack.cpp
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* AudioPort.h - base-class for objects providing sound at a port
|
||||
*
|
||||
* Copyright (c) 2005-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
class EffectChain;
|
||||
|
||||
class AudioPort
|
||||
class AudioPort : public ThreadableJob
|
||||
{
|
||||
public:
|
||||
AudioPort( const QString & _name, bool _has_effect_chain = true );
|
||||
@@ -109,6 +109,13 @@ public:
|
||||
|
||||
bool processEffects();
|
||||
|
||||
// ThreadableJob stuff
|
||||
virtual void doProcessing( sampleFrame * );
|
||||
virtual bool requiresProcessing() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
enum bufferUsages
|
||||
{
|
||||
|
||||
66
include/FxLine.h
Normal file
66
include/FxLine.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* FxLine.h - FX line widget
|
||||
*
|
||||
* Copyright (c) 2009 Andrew Kelley <superjoe30/at/gmail/dot/com>
|
||||
* Copyright (c) 2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* 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 _FX_LINE_H
|
||||
#define _FX_LINE_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
|
||||
#include "knob.h"
|
||||
#include "LcdWidget.h"
|
||||
#include "SendButtonIndicator.h"
|
||||
|
||||
class FxMixerView;
|
||||
class SendButtonIndicator;
|
||||
|
||||
class FxLine : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex);
|
||||
~FxLine();
|
||||
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
virtual void mousePressEvent( QMouseEvent * );
|
||||
virtual void mouseDoubleClickEvent( QMouseEvent * );
|
||||
|
||||
inline int channelIndex() { return m_channelIndex; }
|
||||
void setChannelIndex(int index);
|
||||
|
||||
knob * m_sendKnob;
|
||||
SendButtonIndicator * m_sendBtn;
|
||||
|
||||
private:
|
||||
FxMixerView * m_mv;
|
||||
LcdWidget* m_lcd;
|
||||
|
||||
|
||||
int m_channelIndex;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif // FXLINE_H
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* FxMixer.h - effect-mixer for LMMS
|
||||
*
|
||||
* Copyright (c) 2008-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -29,46 +29,58 @@
|
||||
#include "Mixer.h"
|
||||
#include "EffectChain.h"
|
||||
#include "JournallingObject.h"
|
||||
#include "ThreadableJob.h"
|
||||
|
||||
|
||||
const int NumFxChannels = 64;
|
||||
|
||||
|
||||
struct FxChannel
|
||||
class FxChannel : public ThreadableJob
|
||||
{
|
||||
FxChannel( Model * _parent );
|
||||
~FxChannel();
|
||||
public:
|
||||
FxChannel( int idx, Model * _parent );
|
||||
virtual ~FxChannel();
|
||||
|
||||
EffectChain m_fxChain;
|
||||
bool m_used;
|
||||
bool m_stillRunning;
|
||||
float m_peakLeft;
|
||||
float m_peakRight;
|
||||
sampleFrame * m_buffer;
|
||||
BoolModel m_muteModel;
|
||||
FloatModel m_volumeModel;
|
||||
QString m_name;
|
||||
QMutex m_lock;
|
||||
EffectChain m_fxChain;
|
||||
|
||||
} ;
|
||||
// set to true if any effect in the channel is enabled and running
|
||||
bool m_stillRunning;
|
||||
|
||||
float m_peakLeft;
|
||||
float m_peakRight;
|
||||
sampleFrame * m_buffer;
|
||||
BoolModel m_muteModel;
|
||||
FloatModel m_volumeModel;
|
||||
QString m_name;
|
||||
QMutex m_lock;
|
||||
int m_channelIndex; // what channel index are we
|
||||
bool m_queued; // are we queued up for rendering yet?
|
||||
|
||||
// pointers to other channels that this one sends to
|
||||
QVector<fx_ch_t> m_sends;
|
||||
QVector<FloatModel *> m_sendAmount;
|
||||
|
||||
// pointers to other channels that send to this one
|
||||
QVector<fx_ch_t> m_receives;
|
||||
|
||||
virtual bool requiresProcessing() const { return true; }
|
||||
|
||||
private:
|
||||
virtual void doProcessing( sampleFrame * _working_buffer );
|
||||
};
|
||||
|
||||
|
||||
|
||||
class FxMixer : public JournallingObject, public Model
|
||||
class EXPORT FxMixer : public JournallingObject, public Model
|
||||
{
|
||||
public:
|
||||
FxMixer();
|
||||
virtual ~FxMixer();
|
||||
|
||||
void mixToChannel( const sampleFrame * _buf, fx_ch_t _ch );
|
||||
void processChannel( fx_ch_t _ch, sampleFrame * _buf = NULL );
|
||||
|
||||
void prepareMasterMix();
|
||||
void masterMix( sampleFrame * _buf );
|
||||
|
||||
|
||||
void clear();
|
||||
|
||||
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
|
||||
virtual void loadSettings( const QDomElement & _this );
|
||||
|
||||
@@ -79,17 +91,55 @@ public:
|
||||
|
||||
FxChannel * effectChannel( int _ch )
|
||||
{
|
||||
if( _ch >= 0 && _ch <= NumFxChannels )
|
||||
{
|
||||
return m_fxChannels[_ch];
|
||||
}
|
||||
return NULL;
|
||||
return m_fxChannels[_ch];
|
||||
}
|
||||
|
||||
// make the output of channel fromChannel go to the input of channel toChannel
|
||||
// it is safe to call even if the send already exists
|
||||
void createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel,
|
||||
float amount = 1.0f);
|
||||
|
||||
// delete the connection made by createChannelSend
|
||||
void deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel);
|
||||
|
||||
// determine if adding a send from sendFrom to
|
||||
// sendTo would result in an infinite mixer loop.
|
||||
bool isInfiniteLoop(fx_ch_t fromChannel, fx_ch_t toChannel);
|
||||
|
||||
// return the FloatModel of fromChannel sending its output to the input of
|
||||
// toChannel. NULL if there is no send.
|
||||
FloatModel * channelSendModel(fx_ch_t fromChannel, fx_ch_t toChannel);
|
||||
|
||||
// add a new channel to the Fx Mixer.
|
||||
// returns the index of the channel that was just added
|
||||
int createChannel();
|
||||
|
||||
// delete a channel from the FX mixer.
|
||||
void deleteChannel(int index);
|
||||
|
||||
// delete all the mixer channels except master and remove all effects
|
||||
void clear();
|
||||
|
||||
// re-arrange channels
|
||||
void moveChannelLeft(int index);
|
||||
void moveChannelRight(int index);
|
||||
|
||||
// reset a channel's name, fx, sends, etc
|
||||
void clearChannel(fx_ch_t channelIndex);
|
||||
|
||||
inline fx_ch_t numChannels() const
|
||||
{
|
||||
return m_fxChannels.size();
|
||||
}
|
||||
|
||||
private:
|
||||
FxChannel * m_fxChannels[NumFxChannels+1]; // +1 = master
|
||||
// the fx channels in the mixer. index 0 is always master.
|
||||
QVector<FxChannel *> m_fxChannels;
|
||||
|
||||
// make sure we have at least num channels
|
||||
void allocateChannelsTo(int num);
|
||||
|
||||
void addChannelLeaf( int _ch, sampleFrame * _buf );
|
||||
|
||||
friend class MixerWorkerThread;
|
||||
friend class FxMixerView;
|
||||
|
||||
@@ -26,59 +26,91 @@
|
||||
#define _FX_MIXER_VIEW_H
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QHBoxLayout>
|
||||
#include <QtGui/QScrollArea>
|
||||
|
||||
#include "FxLine.h"
|
||||
#include "FxMixer.h"
|
||||
#include "ModelView.h"
|
||||
#include "engine.h"
|
||||
#include "fader.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "tooltip.h"
|
||||
#include "embed.h"
|
||||
#include "EffectRackView.h"
|
||||
|
||||
class QStackedLayout;
|
||||
class QButtonGroup;
|
||||
class fader;
|
||||
class FxLine;
|
||||
class EffectRackView;
|
||||
class pixmapButton;
|
||||
|
||||
|
||||
class FxMixerView : public QWidget, public ModelView,
|
||||
class EXPORT FxMixerView : public QWidget, public ModelView,
|
||||
public SerializingObjectHook
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct FxChannelView
|
||||
{
|
||||
FxChannelView(QWidget * _parent, FxMixerView * _mv, int _chIndex );
|
||||
|
||||
FxLine * m_fxLine;
|
||||
pixmapButton * m_muteBtn;
|
||||
fader * m_fader;
|
||||
};
|
||||
|
||||
|
||||
FxMixerView();
|
||||
virtual ~FxMixerView();
|
||||
|
||||
virtual void keyPressEvent(QKeyEvent * e);
|
||||
|
||||
virtual void saveSettings( QDomDocument & _doc, QDomElement & _this );
|
||||
virtual void loadSettings( const QDomElement & _this );
|
||||
|
||||
FxLine * currentFxLine()
|
||||
inline FxLine * currentFxLine()
|
||||
{
|
||||
return m_currentFxLine;
|
||||
}
|
||||
|
||||
inline FxChannelView * channelView(int index)
|
||||
{
|
||||
return m_fxChannelViews[index];
|
||||
}
|
||||
|
||||
void setCurrentFxLine( FxLine * _line );
|
||||
void setCurrentFxLine( int _line );
|
||||
|
||||
void clear();
|
||||
|
||||
|
||||
// display the send button and knob correctly
|
||||
void updateFxLine(int index);
|
||||
|
||||
// notify the view that an fx channel was deleted
|
||||
void deleteChannel(int index);
|
||||
|
||||
// move the channel to the left or right
|
||||
void moveChannelLeft(int index);
|
||||
void moveChannelRight(int index);
|
||||
|
||||
// make sure the display syncs up with the fx mixer.
|
||||
// useful for loading projects
|
||||
void refreshDisplay();
|
||||
|
||||
private slots:
|
||||
void updateFaders();
|
||||
|
||||
void addNewChannel();
|
||||
|
||||
private:
|
||||
struct FxChannelView
|
||||
{
|
||||
FxLine * m_fxLine;
|
||||
EffectRackView * m_rackView;
|
||||
pixmapButton * m_muteBtn;
|
||||
fader * m_fader;
|
||||
} ;
|
||||
|
||||
FxChannelView m_fxChannelViews[NumFxChannels+1];
|
||||
QVector<FxChannelView *> m_fxChannelViews;
|
||||
|
||||
QStackedLayout * m_fxRacksLayout;
|
||||
QStackedLayout * m_fxLineBanks;
|
||||
QButtonGroup * m_bankButtons;
|
||||
FxLine * m_currentFxLine;
|
||||
|
||||
QScrollArea * channelArea;
|
||||
QHBoxLayout * chLayout;
|
||||
QWidget * m_channelAreaWidget;
|
||||
EffectRackView * m_rackView;
|
||||
|
||||
void updateMaxChannelSelector();
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
||||
118
include/MixerWorkerThread.h
Normal file
118
include/MixerWorkerThread.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* MixerWorkerThread.h - declaration of class MixerWorkerThread
|
||||
*
|
||||
* Copyright (c) 2009-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* 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 _MIXER_WORKER_THREAD_H
|
||||
#define _MIXER_WORKER_THREAD_H
|
||||
|
||||
#include <QtCore/QAtomicPointer>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include "ThreadableJob.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
class MixerWorkerThread : public QThread
|
||||
{
|
||||
public:
|
||||
// internal representation of the job queue - all functions are thread-safe
|
||||
class JobQueue
|
||||
{
|
||||
public:
|
||||
enum OperationMode
|
||||
{
|
||||
Static, // no jobs added while processing queue
|
||||
Dynamic // jobs can be added while processing queue
|
||||
} ;
|
||||
|
||||
JobQueue() :
|
||||
m_items(),
|
||||
m_queueSize( 0 ),
|
||||
m_itemsDone( 0 ),
|
||||
m_opMode( Static )
|
||||
{
|
||||
}
|
||||
|
||||
void reset( OperationMode _opMode );
|
||||
|
||||
void addJob( ThreadableJob * _job );
|
||||
|
||||
void run( sampleFrame * _buffer );
|
||||
void wait();
|
||||
|
||||
private:
|
||||
#define JOB_QUEUE_SIZE 1024
|
||||
QAtomicPointer<ThreadableJob> m_items[JOB_QUEUE_SIZE];
|
||||
QAtomicInt m_queueSize;
|
||||
QAtomicInt m_itemsDone;
|
||||
OperationMode m_opMode;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
MixerWorkerThread( Mixer* mixer );
|
||||
virtual ~MixerWorkerThread();
|
||||
|
||||
virtual void quit();
|
||||
|
||||
static void resetJobQueue( JobQueue::OperationMode _opMode =
|
||||
JobQueue::Static )
|
||||
{
|
||||
globalJobQueue.reset( _opMode );
|
||||
}
|
||||
|
||||
static void addJob( ThreadableJob * _job )
|
||||
{
|
||||
globalJobQueue.addJob( _job );
|
||||
}
|
||||
|
||||
// a convenient helper function allowing to pass a container with pointers
|
||||
// to ThreadableJob objects
|
||||
template<typename T>
|
||||
static void fillJobQueue( const T & _vec,
|
||||
JobQueue::OperationMode _opMode = JobQueue::Static )
|
||||
{
|
||||
resetJobQueue( _opMode );
|
||||
for( typename T::ConstIterator it = _vec.begin(); it != _vec.end(); ++it )
|
||||
{
|
||||
addJob( *it );
|
||||
}
|
||||
}
|
||||
|
||||
static void startAndWaitForJobs();
|
||||
|
||||
|
||||
private:
|
||||
virtual void run();
|
||||
|
||||
static JobQueue globalJobQueue;
|
||||
static QWaitCondition * queueReadyWaitCond;
|
||||
static QList<MixerWorkerThread *> workerThreads;
|
||||
|
||||
sampleFrame * m_workingBuf;
|
||||
volatile bool m_quit;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -28,12 +28,13 @@
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include "ThreadableJob.h"
|
||||
#include "lmms_basics.h"
|
||||
|
||||
class track;
|
||||
|
||||
|
||||
class PlayHandle
|
||||
class PlayHandle : public ThreadableJob
|
||||
{
|
||||
public:
|
||||
enum Types
|
||||
@@ -72,6 +73,18 @@ public:
|
||||
return m_type;
|
||||
}
|
||||
|
||||
// required for ThreadableJob
|
||||
virtual void doProcessing( sampleFrame* buffer )
|
||||
{
|
||||
play( buffer );
|
||||
}
|
||||
|
||||
virtual bool requiresProcessing() const
|
||||
{
|
||||
return !isFinished();
|
||||
}
|
||||
|
||||
|
||||
virtual void play( sampleFrame* buffer ) = 0;
|
||||
virtual bool isFinished( void ) const = 0;
|
||||
|
||||
|
||||
32
include/SendButtonIndicator.h
Normal file
32
include/SendButtonIndicator.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef SENDBUTTONINDICATOR_H
|
||||
#define SENDBUTTONINDICATOR_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QPixmap>
|
||||
|
||||
#include "FxLine.h"
|
||||
#include "FxMixerView.h"
|
||||
|
||||
class FxLine;
|
||||
class FxMixerView;
|
||||
|
||||
class SendButtonIndicator : public QLabel {
|
||||
public:
|
||||
SendButtonIndicator( QWidget * _parent, FxLine * _owner,
|
||||
FxMixerView * _mv);
|
||||
|
||||
virtual void mousePressEvent( QMouseEvent * e );
|
||||
void updateLightStatus();
|
||||
|
||||
private:
|
||||
|
||||
FxLine * m_parent;
|
||||
FxMixerView * m_mv;
|
||||
QPixmap qpmOn;
|
||||
QPixmap qpmOff;
|
||||
|
||||
FloatModel * getSendModel();
|
||||
};
|
||||
|
||||
#endif // SENDBUTTONINDICATOR_H
|
||||
84
include/ThreadableJob.h
Normal file
84
include/ThreadableJob.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* ThreadableJob.h - declaration of class ThreadableJob
|
||||
*
|
||||
* Copyright (c) 2009-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* 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 _THREADABLE_JOB_H
|
||||
#define _THREADABLE_JOB_H
|
||||
|
||||
#include <QtCore/QAtomicInt>
|
||||
|
||||
#include "lmms_basics.h"
|
||||
|
||||
|
||||
class ThreadableJob
|
||||
{
|
||||
public:
|
||||
|
||||
enum ProcessingState
|
||||
{
|
||||
Unstarted,
|
||||
Queued,
|
||||
InProgress,
|
||||
Done
|
||||
};
|
||||
|
||||
ThreadableJob() :
|
||||
m_state( ThreadableJob::Unstarted )
|
||||
{
|
||||
}
|
||||
|
||||
inline ProcessingState state() const
|
||||
{
|
||||
return static_cast<ProcessingState>( (int) m_state );
|
||||
}
|
||||
|
||||
inline void reset()
|
||||
{
|
||||
m_state = Unstarted;
|
||||
}
|
||||
|
||||
inline void queue()
|
||||
{
|
||||
m_state = Queued;
|
||||
}
|
||||
|
||||
void process( sampleFrame* workingBuffer = NULL )
|
||||
{
|
||||
if( m_state.testAndSetOrdered( Queued, InProgress ) )
|
||||
{
|
||||
doProcessing( workingBuffer );
|
||||
m_state = Done;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool requiresProcessing() const = 0;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void doProcessing( sampleFrame* workingBuffer) = 0;
|
||||
|
||||
QAtomicInt m_state;
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user