mirror of
https://github.com/LMMS/lmms.git
synced 2026-02-02 18:54:29 -05:00
371 lines
8.3 KiB
C++
371 lines
8.3 KiB
C++
/*
|
|
* 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 "PixmapButton.h"
|
|
#include "InstrumentView.h"
|
|
#include "Knob.h"
|
|
#include "LcdSpinBox.h"
|
|
#include "LedCheckbox.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
|