Ability to save mixer sends to disk with the mmp
LMMS can load projects with the old mixer and new projects with the new mixer. By "new mixer", I simply mean not hardcoded to 64 channels.
This commit is contained in:
@@ -280,18 +280,6 @@ signals:
|
||||
inline type maxValue() const \
|
||||
{ \
|
||||
return AutomatableModel::maxValue<type>(); \
|
||||
} \
|
||||
\
|
||||
inline void setMinValue(type val) \
|
||||
{ \
|
||||
m_minValue = val; \
|
||||
if( m_value < m_minValue ) m_value = m_minValue; \
|
||||
} \
|
||||
\
|
||||
inline void setMaxValue(type val) \
|
||||
{ \
|
||||
m_maxValue = val; \
|
||||
if( m_value > m_maxValue ) m_value = m_maxValue; \
|
||||
}
|
||||
|
||||
// some typed AutomatableModel-definitions
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <QLabel>
|
||||
|
||||
#include "knob.h"
|
||||
#include "lcd_spinbox.h"
|
||||
#include "SendButtonIndicator.h"
|
||||
|
||||
class FxMixerView;
|
||||
@@ -15,19 +16,21 @@ 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; }
|
||||
inline void setChannelIndex(int index) { m_channelIndex = index; }
|
||||
void setChannelIndex(int index);
|
||||
|
||||
knob * m_sendKnob;
|
||||
SendButtonIndicator * m_sendBtn;
|
||||
|
||||
private:
|
||||
FxMixerView * m_mv;
|
||||
lcdSpinBox * m_lcd;
|
||||
|
||||
|
||||
int m_channelIndex;
|
||||
|
||||
@@ -73,9 +73,6 @@ public:
|
||||
void prepareMasterMix();
|
||||
void masterMix( sampleFrame * _buf );
|
||||
|
||||
|
||||
void clear();
|
||||
|
||||
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
|
||||
virtual void loadSettings( const QDomElement & _this );
|
||||
|
||||
@@ -112,6 +109,9 @@ public:
|
||||
// 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);
|
||||
@@ -128,6 +128,9 @@ private:
|
||||
// the fx channels in the mixer. index 0 is always master.
|
||||
QVector<FxChannel *> m_fxChannels;
|
||||
|
||||
|
||||
void allocateChannelsTo(int num);
|
||||
|
||||
friend class mixerWorkerThread;
|
||||
friend class FxMixerView;
|
||||
|
||||
|
||||
@@ -91,6 +91,10 @@ public:
|
||||
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();
|
||||
|
||||
@@ -442,13 +442,16 @@ void FxMixer::masterMix( sampleFrame * _buf )
|
||||
|
||||
void FxMixer::clear()
|
||||
{
|
||||
for( int i = 0; i < m_fxChannels.size(); ++i )
|
||||
while( m_fxChannels.size() > 1 )
|
||||
{
|
||||
clearChannel(i);
|
||||
deleteChannel(1);
|
||||
}
|
||||
|
||||
clearChannel(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FxMixer::clearChannel(fx_ch_t index)
|
||||
{
|
||||
FxChannel * ch = m_fxChannels[index];
|
||||
@@ -483,38 +486,94 @@ void FxMixer::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
{
|
||||
for( int i = 0; i < m_fxChannels.size(); ++i )
|
||||
{
|
||||
FxChannel * ch = m_fxChannels[i];
|
||||
|
||||
QDomElement fxch = _doc.createElement( QString( "fxchannel" ) );
|
||||
_this.appendChild( fxch );
|
||||
m_fxChannels[i]->m_fxChain.saveState( _doc, fxch );
|
||||
m_fxChannels[i]->m_volumeModel.saveSettings( _doc, fxch,
|
||||
"volume" );
|
||||
m_fxChannels[i]->m_muteModel.saveSettings( _doc, fxch,
|
||||
"muted" );
|
||||
|
||||
ch->m_fxChain.saveState( _doc, fxch );
|
||||
ch->m_volumeModel.saveSettings( _doc, fxch, "volume" );
|
||||
ch->m_muteModel.saveSettings( _doc, fxch, "muted" );
|
||||
fxch.setAttribute( "num", i );
|
||||
fxch.setAttribute( "name", m_fxChannels[i]->m_name );
|
||||
fxch.setAttribute( "name", ch->m_name );
|
||||
|
||||
// add the channel sends
|
||||
for( int si = 0; si < ch->m_sends.size(); ++si )
|
||||
{
|
||||
QDomElement sendsDom = _doc.createElement( QString( "send" ) );
|
||||
fxch.appendChild( sendsDom );
|
||||
|
||||
sendsDom.setAttribute( "channel", ch->m_sends[si] );
|
||||
ch->m_sendAmount[si]->saveSettings( _doc, sendsDom, "amount");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FxMixer::allocateChannelsTo(int num)
|
||||
{
|
||||
while( num > m_fxChannels.size() - 1 )
|
||||
{
|
||||
createChannel();
|
||||
|
||||
// delete the default send to master
|
||||
deleteChannelSend(m_fxChannels.size()-1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FxMixer::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
clear();
|
||||
QDomNode node = _this.firstChild();
|
||||
for( int i = 0; i <= 64; ++i ) // TODO make this work
|
||||
bool thereIsASend = false;
|
||||
|
||||
while( ! node.isNull() )
|
||||
{
|
||||
QDomElement fxch = node.toElement();
|
||||
|
||||
// index of the channel we are about to load
|
||||
int num = fxch.attribute( "num" ).toInt();
|
||||
m_fxChannels[num]->m_fxChain.restoreState(
|
||||
fxch.firstChildElement(
|
||||
m_fxChannels[num]->m_fxChain.nodeName() ) );
|
||||
|
||||
// allocate enough channels
|
||||
allocateChannelsTo( num );
|
||||
|
||||
m_fxChannels[num]->m_volumeModel.loadSettings( fxch, "volume" );
|
||||
m_fxChannels[num]->m_muteModel.loadSettings( fxch, "muted" );
|
||||
m_fxChannels[num]->m_name = fxch.attribute( "name" );
|
||||
|
||||
m_fxChannels[num]->m_fxChain.restoreState( fxch.firstChildElement(
|
||||
m_fxChannels[num]->m_fxChain.nodeName() ) );
|
||||
|
||||
// mixer sends
|
||||
QDomNodeList chData = fxch.childNodes();
|
||||
for( unsigned int i=0; i<chData.length(); ++i )
|
||||
{
|
||||
QDomElement chDataItem = chData.at(i).toElement();
|
||||
if( chDataItem.nodeName() == QString( "send" ) )
|
||||
{
|
||||
thereIsASend = true;
|
||||
int sendTo = chDataItem.attribute( "channel" ).toInt();
|
||||
allocateChannelsTo( sendTo) ;
|
||||
float amount = chDataItem.attribute( "amount" ).toFloat();
|
||||
createChannelSend( num, sendTo, amount );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
node = node.nextSibling();
|
||||
}
|
||||
|
||||
// check for old format. 65 fx channels and no explicit sends.
|
||||
if( ! thereIsASend && m_fxChannels.size() == 65 ) {
|
||||
// create a send from every channel into master
|
||||
for( int i=1; i<m_fxChannels.size(); ++i )
|
||||
{
|
||||
createChannelSend(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
emit dataChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -904,6 +904,23 @@ void song::loadProject( const QString & _file_name )
|
||||
firstChildElement( "track" ) );
|
||||
}
|
||||
QDomNode node = mmp.content().firstChild();
|
||||
|
||||
// walk through and fix up the mixer
|
||||
while( !node.isNull() )
|
||||
{
|
||||
if( node.nodeName() == engine::fxMixer()->nodeName() )
|
||||
{
|
||||
engine::fxMixer()->restoreState( node.toElement() );
|
||||
|
||||
// refresh FxMixerView
|
||||
engine::fxMixerView()->refreshDisplay();
|
||||
}
|
||||
|
||||
node = node.nextSibling();
|
||||
}
|
||||
|
||||
node = mmp.content().firstChild();
|
||||
|
||||
while( !node.isNull() )
|
||||
{
|
||||
if( node.isElement() )
|
||||
@@ -917,10 +934,6 @@ void song::loadProject( const QString & _file_name )
|
||||
{
|
||||
restoreControllerStates( node.toElement() );
|
||||
}
|
||||
else if( node.nodeName() == engine::fxMixer()->nodeName() )
|
||||
{
|
||||
engine::fxMixer()->restoreState( node.toElement() );
|
||||
}
|
||||
else if( engine::hasGUI() )
|
||||
{
|
||||
if( node.nodeName() ==
|
||||
@@ -973,7 +986,6 @@ void song::loadProject( const QString & _file_name )
|
||||
// resolve all IDs so that autoModels are automated
|
||||
automationPattern::resolveAllIDs();
|
||||
|
||||
|
||||
engine::getMixer()->unlock();
|
||||
|
||||
configManager::inst()->addRecentlyOpenedProject( _file_name );
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "FxMixerView.h"
|
||||
#include "embed.h"
|
||||
#include "engine.h"
|
||||
#include "lcd_spinbox.h"
|
||||
#include "SendButtonIndicator.h"
|
||||
|
||||
FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) :
|
||||
@@ -32,11 +31,27 @@ FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) :
|
||||
m_sendBtn->move(4,4);
|
||||
|
||||
// channel number
|
||||
lcdSpinBox * l = new lcdSpinBox( 2, this );
|
||||
l->model()->setRange( m_channelIndex, m_channelIndex );
|
||||
l->model()->setValue( m_channelIndex );
|
||||
l->move( 2, 58 );
|
||||
l->setMarginWidth( 1 );
|
||||
m_lcd = new lcdSpinBox( 2, this );
|
||||
m_lcd->model()->setRange( m_channelIndex, m_channelIndex );
|
||||
m_lcd->model()->setValue( m_channelIndex );
|
||||
m_lcd->move( 2, 58 );
|
||||
m_lcd->setMarginWidth( 1 );
|
||||
}
|
||||
|
||||
FxLine::~FxLine()
|
||||
{
|
||||
delete m_sendKnob;
|
||||
delete m_sendBtn;
|
||||
delete m_lcd;
|
||||
}
|
||||
|
||||
|
||||
void FxLine::setChannelIndex(int index) {
|
||||
m_channelIndex = index;
|
||||
|
||||
m_lcd->model()->setRange( m_channelIndex, m_channelIndex );
|
||||
m_lcd->model()->setValue( m_channelIndex );
|
||||
m_lcd->update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -91,8 +91,8 @@ FxMixerView::FxMixerView() :
|
||||
m_fxChannelViews[i] = new FxChannelView(m_channelAreaWidget, this, i);
|
||||
chLayout->addWidget(m_fxChannelViews[i]->m_fxLine);
|
||||
}
|
||||
// add the scrolling section to the main layout
|
||||
|
||||
// add the scrolling section to the main layout
|
||||
// class solely for scroll area to pass key presses down
|
||||
class ChannelArea : public QScrollArea
|
||||
{
|
||||
@@ -175,6 +175,32 @@ void FxMixerView::addNewChannel()
|
||||
}
|
||||
|
||||
|
||||
void FxMixerView::refreshDisplay()
|
||||
{
|
||||
// delete all views and re-add them
|
||||
for( int i = 1; i<m_fxChannelViews.size(); ++i )
|
||||
{
|
||||
chLayout->removeWidget(m_fxChannelViews[i]->m_fxLine);
|
||||
delete m_fxChannelViews[i]->m_fader;
|
||||
delete m_fxChannelViews[i]->m_muteBtn;
|
||||
delete m_fxChannelViews[i]->m_fxLine;
|
||||
delete m_fxChannelViews[i];
|
||||
}
|
||||
m_channelAreaWidget->adjustSize();
|
||||
|
||||
// re-add the views
|
||||
m_fxChannelViews.resize(engine::fxMixer()->numChannels());
|
||||
for( int i = 1; i < m_fxChannelViews.size(); ++i )
|
||||
{
|
||||
m_fxChannelViews[i] = new FxChannelView(m_channelAreaWidget, this, i);
|
||||
chLayout->addWidget(m_fxChannelViews[i]->m_fxLine);
|
||||
}
|
||||
|
||||
// fix master
|
||||
//TODO
|
||||
}
|
||||
|
||||
|
||||
void FxMixerView::updateMaxChannelSelector()
|
||||
{
|
||||
// update the and max. channel number for every instrument
|
||||
@@ -190,8 +216,8 @@ void FxMixerView::updateMaxChannelSelector()
|
||||
if( trackList[i]->type() == track::InstrumentTrack )
|
||||
{
|
||||
InstrumentTrack * inst = (InstrumentTrack *) trackList[i];
|
||||
inst->effectChannelModel()->setMaxValue(
|
||||
m_fxChannelViews.size()-1);
|
||||
inst->effectChannelModel()->setRange(0,
|
||||
m_fxChannelViews.size()-1,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user