Merge pull request #1234 from floft/master

GIG Player Plugin
This commit is contained in:
Vesa V
2014-11-25 07:03:12 +02:00
15 changed files with 2537 additions and 1 deletions

View File

@@ -26,6 +26,7 @@ ADD_SUBDIRECTORY(peak_controller_effect)
IF(NOT LMMS_BUILD_APPLE)
ADD_SUBDIRECTORY(sf2_player)
ENDIF()
ADD_SUBDIRECTORY(GigPlayer)
ADD_SUBDIRECTORY(sfxr)
ADD_SUBDIRECTORY(sid)
ADD_SUBDIRECTORY(SpectrumAnalyzer)

View File

@@ -0,0 +1,13 @@
if(LMMS_HAVE_GIG)
INCLUDE(BuildPlugin)
INCLUDE_DIRECTORIES(${GIG_INCLUDE_DIRS})
# Required for not crashing loading files with libgig
SET(GCC_COVERAGE_COMPILE_FLAGS "-fexceptions")
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
LINK_DIRECTORIES(${GIG_LIBRARY_DIRS})
LINK_LIBRARIES(${GIG_LIBRARIES})
BUILD_PLUGIN(gigplayer GigPlayer.cpp GigPlayer.h PatchesDialog.cpp PatchesDialog.h PatchesDialog.ui MOCFILES GigPlayer.h PatchesDialog.h UICFILES PatchesDialog.ui EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
endif(LMMS_HAVE_GIG)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,370 @@
/*
* GigPlayer.h - a GIG player using libgig (based on Sf2 player plugin)
*
* Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
* 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 GIG_PLAYER_H
#define GIG_PLAYER_H
#include <QList>
#include <QMutex>
#include <QMutexLocker>
#include "Instrument.h"
#include "pixmap_button.h"
#include "InstrumentView.h"
#include "knob.h"
#include "LcdSpinBox.h"
#include "led_checkbox.h"
#include "SampleBuffer.h"
#include "MemoryManager.h"
#include "gig.h"
class GigInstrumentView;
class NotePlayHandle;
class PatchesDialog;
class QLabel;
struct GIGPluginData
{
int midiNote;
} ;
// Load a GIG file using libgig
class GigInstance
{
public:
GigInstance( QString filename ) :
riff( filename.toUtf8().constData() ),
gig( &riff )
{}
private:
RIFF::File riff;
public:
gig::File gig;
} ;
// Stores options for the notes, e.g. velocity and release time
struct Dimension
{
Dimension() :
release( false )
{
for( int i = 0; i < 8; ++i )
{
DimValues[i] = 0;
}
}
uint DimValues[8];
bool release;
} ;
// Takes information from the GIG file for a certain note and provides the
// amplitude (0-1) to multiply the signal by (internally incrementing the
// position in the envelope when asking for the amplitude).
class ADSR
{
// From the file
float preattack; // initial amplitude (0-1)
float attack; // 0-60s
float decay1; // 0-60s
float decay2; // 0-60s
bool infiniteSustain; // i.e., no decay2
float sustain; // sustain amplitude (0-1)
float release; // 0-60s
// Used to calculate current amplitude
float amplitude;
bool isAttack;
bool isRelease;
bool isDone;
f_cnt_t attackPosition;
f_cnt_t attackLength;
f_cnt_t decayLength;
f_cnt_t releasePosition;
f_cnt_t releaseLength;
public:
ADSR();
ADSR( gig::DimensionRegion * region, int sampleRate );
void keyup(); // We will begin releasing starting now
bool done(); // Is this sample done playing?
float value(); // What's the current amplitude
void inc( f_cnt_t num ); // Increment internal positions by num
} ;
// The sample from the GIG file with our current position in both the sample
// and the envelope
class GigSample
{
public:
GigSample( gig::Sample * pSample, gig::DimensionRegion * pDimRegion,
float attenuation, int interpolation, float desiredFreq );
~GigSample();
// Needed when initially creating in QList
GigSample( const GigSample& g );
GigSample& operator=( const GigSample& g );
// Needed since libsamplerate stores data internally between calls
void updateSampleRate();
bool convertSampleRate( sampleFrame & oldBuf, sampleFrame & newBuf,
f_cnt_t oldSize, f_cnt_t newSize, float freq_factor, f_cnt_t& used );
gig::Sample * sample;
gig::DimensionRegion * region;
float attenuation;
ADSR adsr;
// The position in sample
f_cnt_t pos;
// Whether to change the pitch of the samples, e.g. if there's only one
// sample per octave and you want that sample pitch shifted for the rest of
// the notes in the octave, this will be true
bool pitchtrack;
// Used to convert sample rates
int interpolation;
SRC_STATE * srcState;
// Used changing the pitch of the note if desired
float sampleFreq;
float freqFactor;
} ;
// What portion of a note are we in?
enum GigState
{
// We just pressed the key
KeyDown,
// The note is currently playing
PlayingKeyDown,
// We just released the key
KeyUp,
// The note is being released, e.g. a release sample is playing
PlayingKeyUp,
// The note is done playing, you can delete this note now
Completed
} ;
// Corresponds to a certain midi note pressed, but may contain multiple samples
class GigNote
{
public:
int midiNote;
int velocity;
bool release; // Whether to trigger a release sample on key up
bool isRelease; // Whether this is a release sample, changes when we delete it
GigState state;
float frequency;
QList<GigSample> samples;
// Used to determine which note should be released on key up
//
// Note: if accessing the data, be careful not to access it after the key
// has been released since that's when it is deleted
GIGPluginData * handle;
GigNote( int midiNote, int velocity, float frequency, GIGPluginData * handle )
: midiNote( midiNote ), velocity( velocity ),
release( false ), isRelease( false ), state( KeyDown ),
frequency( frequency ), handle( handle )
{
}
} ;
class GigInstrument : public Instrument
{
Q_OBJECT
MM_OPERATORS
mapPropertyFromModel( int, getBank, setBank, m_bankNum );
mapPropertyFromModel( int, getPatch, setPatch, m_patchNum );
public:
GigInstrument( InstrumentTrack * _instrument_track );
virtual ~GigInstrument();
virtual void play( sampleFrame * _working_buffer );
virtual void playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer );
virtual void deleteNotePluginData( NotePlayHandle * _n );
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
virtual void loadSettings( const QDomElement & _this );
virtual void loadFile( const QString & _file );
virtual AutomatableModel * childModel( const QString & _modelName );
virtual QString nodeName() const;
virtual f_cnt_t desiredReleaseFrames() const
{
return 0;
}
virtual Flags flags() const
{
return IsSingleStreamed|IsNotBendable;
}
virtual PluginView * instantiateView( QWidget * _parent );
QString getCurrentPatchName();
void setParameter( const QString & _param, const QString & _value );
public slots:
void openFile( const QString & _gigFile, bool updateTrackName = true );
void updatePatch();
void updateSampleRate();
private:
// The GIG file and instrument we're using
GigInstance * m_instance;
gig::Instrument * m_instrument;
// Part of the UI
QString m_filename;
LcdSpinBoxModel m_bankNum;
LcdSpinBoxModel m_patchNum;
FloatModel m_gain;
// Locking for the data
QMutex m_synthMutex;
QMutex m_notesMutex;
// Used for resampling
int m_interpolation;
// List of all the currently playing notes
QList<GigNote> m_notes;
// Used when determining which samples to use
uint32_t m_RandomSeed;
float m_currentKeyDimension;
private:
// Delete the current GIG instance if one is open
void freeInstance();
// Open the instrument in the currently-open GIG file
void getInstrument();
// Create "dimension" to select desired samples from GIG file based on
// parameters such as velocity
Dimension getDimensions( gig::Region * pRegion, int velocity, bool release );
// Load sample data from the Gig file, looping the sample where needed
void loadSample( GigSample& sample, sampleFrame* sampleData, f_cnt_t samples );
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;
// Add the desired samples to the note, either normal samples or release
// samples
void addSamples( GigNote & gignote, bool wantReleaseSample );
friend class GigInstrumentView;
signals:
void fileLoading();
void fileChanged();
void patchChanged();
} ;
class GigInstrumentView : public InstrumentView
{
Q_OBJECT
public:
GigInstrumentView( Instrument * _instrument,
QWidget * _parent );
virtual ~GigInstrumentView();
private:
virtual void modelChanged();
pixmapButton * m_fileDialogButton;
pixmapButton * m_patchDialogButton;
LcdSpinBox * m_bankNumLcd;
LcdSpinBox * m_patchNumLcd;
QLabel * m_filenameLabel;
QLabel * m_patchLabel;
knob * m_gainKnob;
static PatchesDialog * s_patchDialog;
protected slots:
void invalidateFile();
void showFileDialog();
void showPatchDialog();
void updateFilename();
void updatePatchName();
} ;
#endif

View File

@@ -0,0 +1,414 @@
/*
* PatchesDialog.cpp - display GIG patches (based on Sf2 patches_dialog.cpp)
*
* Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
*
* 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.
*
*/
#include "PatchesDialog.h"
#include <QHeaderView>
// Custom list-view item (as for numerical sort purposes...)
class PatchItem : public QTreeWidgetItem
{
public:
// Constructor.
PatchItem( QTreeWidget *pListView,
QTreeWidgetItem *pItemAfter )
: QTreeWidgetItem( pListView, pItemAfter ) {}
// Sort/compare overriden method.
bool operator< ( const QTreeWidgetItem& other ) const
{
int iColumn = QTreeWidgetItem::treeWidget()->sortColumn();
const QString& s1 = text( iColumn );
const QString& s2 = other.text( iColumn );
if( iColumn == 0 || iColumn == 2 )
{
return s1.toInt() < s2.toInt();
}
else
{
return s1 < s2;
}
}
};
// Constructor.
PatchesDialog::PatchesDialog( QWidget * pParent, Qt::WindowFlags wflags )
: QDialog( pParent, wflags )
{
// Setup UI struct...
setupUi( this );
m_pSynth = NULL;
m_iChan = 0;
m_iBank = 0;
m_iProg = 0;
// Soundfonts list view...
QHeaderView * pHeader = m_progListView->header();
pHeader->setDefaultAlignment( Qt::AlignLeft );
#if QT_VERSION >= 0x050000
pHeader->setSectionsMovable( false );
#else
pHeader->setMovable( false );
#endif
pHeader->setStretchLastSection( true );
m_progListView->resizeColumnToContents( 0 ); // Prog.
// Initial sort order...
m_bankListView->sortItems( 0, Qt::AscendingOrder );
m_progListView->sortItems( 0, Qt::AscendingOrder );
// UI connections...
QObject::connect( m_bankListView,
SIGNAL( currentItemChanged( QTreeWidgetItem *,QTreeWidgetItem * ) ),
SLOT( bankChanged() ) );
QObject::connect( m_progListView,
SIGNAL( currentItemChanged( QTreeWidgetItem *, QTreeWidgetItem * ) ),
SLOT( progChanged( QTreeWidgetItem *, QTreeWidgetItem * ) ) );
QObject::connect( m_progListView,
SIGNAL( itemActivated( QTreeWidgetItem *, int ) ),
SLOT( accept() ) );
QObject::connect( m_okButton,
SIGNAL( clicked() ),
SLOT( accept() ) );
QObject::connect( m_cancelButton,
SIGNAL( clicked() ),
SLOT( reject() ) );
}
// Destructor.
PatchesDialog::~PatchesDialog()
{
}
// Dialog setup loader.
void PatchesDialog::setup( GigInstance * pSynth, int iChan,
const QString & chanName,
LcdSpinBoxModel * bankModel,
LcdSpinBoxModel * progModel,
QLabel * patchLabel )
{
// We'll going to changes the whole thing...
m_dirty = 0;
m_bankModel = bankModel;
m_progModel = progModel;
m_patchLabel = patchLabel;
// Set the proper caption...
setWindowTitle( chanName + " - GIG patches" );
// set m_pSynth to NULL so we don't trigger any progChanged events
m_pSynth = NULL;
// Load bank list from actual synth stack...
m_bankListView->setSortingEnabled( false );
m_bankListView->clear();
// now it should be safe to set internal stuff
m_pSynth = pSynth;
m_iChan = iChan;
//fluid_preset_t preset;
QTreeWidgetItem * pBankItem = NULL;
// Currently just use zero as the only bank
int iBankDefault = -1;
int iProgDefault = -1;
gig::Instrument * pInstrument = m_pSynth->gig.GetFirstInstrument();
while( pInstrument )
{
int iBank = pInstrument->MIDIBank;
int iProg = pInstrument->MIDIProgram;
if ( !findBankItem( iBank ) )
{
pBankItem = new PatchItem( m_bankListView, pBankItem );
if( pBankItem )
{
pBankItem->setText( 0, QString::number( iBank ) );
if( iBankDefault == -1 )
{
iBankDefault = iBank;
iProgDefault = iProg;
}
}
}
pInstrument = m_pSynth->gig.GetNextInstrument();
}
m_bankListView->setSortingEnabled( true );
// Set the selected bank.
if( iBankDefault != -1 )
{
m_iBank = iBankDefault;
}
pBankItem = findBankItem( m_iBank );
m_bankListView->setCurrentItem( pBankItem );
m_bankListView->scrollToItem( pBankItem );
bankChanged();
// Set the selected program.
if( iProgDefault != -1 )
{
m_iProg = iProgDefault;
}
QTreeWidgetItem * pProgItem = findProgItem( m_iProg );
m_progListView->setCurrentItem( pProgItem );
m_progListView->scrollToItem( pProgItem );
}
// Stabilize current state form.
void PatchesDialog::stabilizeForm()
{
m_okButton->setEnabled( validateForm() );
}
// Validate form fields.
bool PatchesDialog::validateForm()
{
bool bValid = true;
bValid = bValid && ( m_bankListView->currentItem() != NULL );
bValid = bValid && ( m_progListView->currentItem() != NULL );
return bValid;
}
// Realize a bank-program selection preset.
void PatchesDialog::setBankProg( int iBank, int iProg )
{
if( m_pSynth == NULL )
{
return;
}
}
// Validate form fields and accept it valid.
void PatchesDialog::accept()
{
if( validateForm() )
{
// Unload from current selected dialog items.
int iBank = ( m_bankListView->currentItem() )->text( 0 ).toInt();
int iProg = ( m_progListView->currentItem() )->text( 0 ).toInt();
// And set it right away...
setBankProg( iBank, iProg );
if( m_dirty > 0 )
{
m_bankModel->setValue( iBank );
m_progModel->setValue( iProg );
m_patchLabel->setText( m_progListView->
currentItem()->text( 1 ) );
}
// We got it.
QDialog::accept();
}
}
// Reject settings (Cancel button slot).
void PatchesDialog::reject()
{
// Reset selection to initial selection, if applicable...
if( m_dirty > 0 )
{
setBankProg( m_bankModel->value(), m_progModel->value() );
}
// Done (hopefully nothing).
QDialog::reject();
}
// Find the bank item of given bank number id.
QTreeWidgetItem * PatchesDialog::findBankItem( int iBank )
{
QList<QTreeWidgetItem *> banks
= m_bankListView->findItems(
QString::number( iBank ), Qt::MatchExactly, 0 );
QListIterator<QTreeWidgetItem *> iter( banks );
if( iter.hasNext() )
{
return iter.next();
}
else
{
return NULL;
}
}
// Find the program item of given program number id.
QTreeWidgetItem *PatchesDialog::findProgItem( int iProg )
{
QList<QTreeWidgetItem *> progs
= m_progListView->findItems(
QString::number( iProg ), Qt::MatchExactly, 0 );
QListIterator<QTreeWidgetItem *> iter( progs );
if( iter.hasNext() )
{
return iter.next();
}
else
{
return NULL;
}
}
// Bank change slot.
void PatchesDialog::bankChanged()
{
if( m_pSynth == NULL )
{
return;
}
QTreeWidgetItem * pBankItem = m_bankListView->currentItem();
if( pBankItem == NULL )
{
return;
}
int iBankSelected = pBankItem->text( 0 ).toInt();
// Clear up the program listview.
m_progListView->setSortingEnabled( false );
m_progListView->clear();
QTreeWidgetItem * pProgItem = NULL;
gig::Instrument * pInstrument = m_pSynth->gig.GetFirstInstrument();
while( pInstrument )
{
QString name = QString::fromStdString( pInstrument->pInfo->Name );
if( name == "" )
{
name = "<no name>";
}
int iBank = pInstrument->MIDIBank;
int iProg = pInstrument->MIDIProgram;
if( iBank == iBankSelected && !findProgItem( iProg ) )
{
pProgItem = new PatchItem( m_progListView, pProgItem );
if( pProgItem )
{
pProgItem->setText( 0, QString::number( iProg ) );
pProgItem->setText( 1, name );
}
}
pInstrument = m_pSynth->gig.GetNextInstrument();
}
m_progListView->setSortingEnabled( true );
// Stabilize the form.
stabilizeForm();
}
// Program change slot.
void PatchesDialog::progChanged( QTreeWidgetItem * curr, QTreeWidgetItem * prev )
{
if( m_pSynth == NULL || curr == NULL )
{
return;
}
// Which preview state...
if( validateForm() )
{
// Set current selection.
int iBank = ( m_bankListView->currentItem() )->text( 0 ).toInt();
int iProg = curr->text( 0 ).toInt();
// And set it right away...
setBankProg( iBank, iProg );
// Now we're dirty nuff.
m_dirty++;
}
// Stabilize the form.
stabilizeForm();
}

View File

@@ -0,0 +1,92 @@
/*
* PatchesDialog.h - display GIG patches (based on Sf2 patches_dialog.h)
*
* Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
*
* 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 PATCHES_DIALOG_H
#define PATCHES_DIALOG_H
#include "ui_PatchesDialog.h"
#include "LcdSpinBox.h"
#include "GigPlayer.h"
#include <fluidsynth.h>
#include <QWidget>
#include <QLabel>
//----------------------------------------------------------------------------
// qsynthPresetForm -- UI wrapper form.
class PatchesDialog : public QDialog, private Ui::PatchesDialog
{
Q_OBJECT
public:
// Constructor.
PatchesDialog( QWidget * pParent = 0, Qt::WindowFlags wflags = 0 );
// Destructor.
virtual ~PatchesDialog();
void setup( GigInstance * pSynth, int iChan, const QString & chanName,
LcdSpinBoxModel * bankModel, LcdSpinBoxModel * progModel, QLabel * patchLabel );
public slots:
void stabilizeForm();
void bankChanged();
void progChanged( QTreeWidgetItem * curr, QTreeWidgetItem * prev );
protected slots:
void accept();
void reject();
protected:
void setBankProg( int iBank, int iProg );
QTreeWidgetItem * findBankItem( int iBank );
QTreeWidgetItem * findProgItem( int iProg );
bool validateForm();
private:
// Instance variables.
GigInstance * m_pSynth;
int m_iChan;
int m_iBank;
int m_iProg;
int m_dirty;
LcdSpinBoxModel * m_bankModel;
LcdSpinBoxModel * m_progModel;
QLabel * m_patchLabel;
};
#endif

View File

@@ -0,0 +1,216 @@
<ui version="4.0" >
<author>rncbc aka Rui Nuno Capela</author>
<comment>qsynth - A fluidsynth Qt GUI Interface.
Copyright (C) 2003-2007, rncbc aka Rui Nuno Capela. All rights reserved.
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; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
</comment>
<class>PatchesDialog</class>
<widget class="QDialog" name="PatchesDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>480</width>
<height>350</height>
</rect>
</property>
<property name="minimumSize" >
<size>
<width>300</width>
<height>150</height>
</size>
</property>
<property name="windowTitle" >
<string>Qsynth: Channel Preset</string>
</property>
<property name="windowIcon" >
<iconset/>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QSplitter" name="m_splitter" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeWidget" name="m_bankListView" >
<property name="minimumSize" >
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>80</width>
<height>32767</height>
</size>
</property>
<property name="toolTip" >
<string>Bank selector</string>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="indentation" >
<number>4</number>
</property>
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
<property name="uniformRowHeights" >
<bool>true</bool>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
<property name="sortingEnabled" >
<bool>true</bool>
</property>
<property name="allColumnsShowFocus" >
<bool>true</bool>
</property>
<column>
<property name="text" >
<string>Bank</string>
</property>
</column>
</widget>
<widget class="QTreeWidget" name="m_progListView" >
<property name="toolTip" >
<string>Program selector</string>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="indentation" >
<number>4</number>
</property>
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
<property name="uniformRowHeights" >
<bool>true</bool>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
<property name="sortingEnabled" >
<bool>true</bool>
</property>
<property name="allColumnsShowFocus" >
<bool>true</bool>
</property>
<column>
<property name="text" >
<string>Patch</string>
</property>
</column>
<column>
<property name="text" >
<string>Name</string>
</property>
</column>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>4</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>120</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_okButton" >
<property name="toolTip" >
<string/>
</property>
<property name="text" >
<string>OK</string>
</property>
<property name="iconSize" >
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="default" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_cancelButton" >
<property name="toolTip" >
<string/>
</property>
<property name="text" >
<string>Cancel</string>
</property>
<property name="iconSize" >
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<layoutdefault spacing="4" margin="4" />
<tabstops>
<tabstop>m_okButton</tabstop>
<tabstop>m_cancelButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
plugins/GigPlayer/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 B