1 /* 2 * GigPlayer.h - a GIG player using libgig (based on Sf2 player plugin) 3 * 4 * Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com> 5 * Copyright (c) 2009-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net> 6 * 7 * This file is part of LMMS - https://lmms.io 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public 20 * License along with this program (see COPYING); if not, write to the 21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301 USA. 23 * 24 */ 25 26 27 #ifndef GIG_PLAYER_H 28 #define GIG_PLAYER_H 29 30 #include <QList> 31 #include <QMutex> 32 #include <QMutexLocker> 33 #include <samplerate.h> 34 35 #include "Instrument.h" 36 #include "PixmapButton.h" 37 #include "InstrumentView.h" 38 #include "Knob.h" 39 #include "LcdSpinBox.h" 40 #include "LedCheckbox.h" 41 #include "MemoryManager.h" 42 #include "gig.h" 43 44 class GigInstrumentView; 45 class NotePlayHandle; 46 47 class PatchesDialog; 48 class QLabel; 49 50 51 52 53 struct GIGPluginData 54 { 55 int midiNote; 56 } ; 57 58 59 60 61 // Load a GIG file using libgig 62 class GigInstance 63 { 64 public: GigInstance(QString filename)65 GigInstance( QString filename ) : 66 riff( filename.toUtf8().constData() ), 67 gig( &riff ) 68 {} 69 70 private: 71 RIFF::File riff; 72 73 public: 74 gig::File gig; 75 } ; 76 77 78 79 80 // Stores options for the notes, e.g. velocity and release time 81 struct Dimension 82 { DimensionDimension83 Dimension() : 84 release( false ) 85 { 86 for( int i = 0; i < 8; ++i ) 87 { 88 DimValues[i] = 0; 89 } 90 } 91 92 uint DimValues[8]; 93 bool release; 94 } ; 95 96 97 98 99 // Takes information from the GIG file for a certain note and provides the 100 // amplitude (0-1) to multiply the signal by (internally incrementing the 101 // position in the envelope when asking for the amplitude). 102 class ADSR 103 { 104 // From the file 105 float preattack; // initial amplitude (0-1) 106 float attack; // 0-60s 107 float decay1; // 0-60s 108 float decay2; // 0-60s 109 bool infiniteSustain; // i.e., no decay2 110 float sustain; // sustain amplitude (0-1) 111 float release; // 0-60s 112 113 // Used to calculate current amplitude 114 float amplitude; 115 bool isAttack; 116 bool isRelease; 117 bool isDone; 118 f_cnt_t attackPosition; 119 f_cnt_t attackLength; 120 f_cnt_t decayLength; 121 f_cnt_t releasePosition; 122 f_cnt_t releaseLength; 123 124 public: 125 ADSR(); 126 ADSR( gig::DimensionRegion * region, int sampleRate ); 127 void keyup(); // We will begin releasing starting now 128 bool done(); // Is this sample done playing? 129 float value(); // What's the current amplitude 130 void inc( f_cnt_t num ); // Increment internal positions by num 131 } ; 132 133 134 135 136 // The sample from the GIG file with our current position in both the sample 137 // and the envelope 138 class GigSample 139 { 140 public: 141 GigSample( gig::Sample * pSample, gig::DimensionRegion * pDimRegion, 142 float attenuation, int interpolation, float desiredFreq ); 143 ~GigSample(); 144 145 // Needed when initially creating in QList 146 GigSample( const GigSample& g ); 147 GigSample& operator=( const GigSample& g ); 148 149 // Needed since libsamplerate stores data internally between calls 150 void updateSampleRate(); 151 bool convertSampleRate( sampleFrame & oldBuf, sampleFrame & newBuf, 152 f_cnt_t oldSize, f_cnt_t newSize, float freq_factor, f_cnt_t& used ); 153 154 gig::Sample * sample; 155 gig::DimensionRegion * region; 156 float attenuation; 157 ADSR adsr; 158 159 // The position in sample 160 f_cnt_t pos; 161 162 // Whether to change the pitch of the samples, e.g. if there's only one 163 // sample per octave and you want that sample pitch shifted for the rest of 164 // the notes in the octave, this will be true 165 bool pitchtrack; 166 167 // Used to convert sample rates 168 int interpolation; 169 SRC_STATE * srcState; 170 171 // Used changing the pitch of the note if desired 172 float sampleFreq; 173 float freqFactor; 174 } ; 175 176 177 178 179 // What portion of a note are we in? 180 enum GigState 181 { 182 // We just pressed the key 183 KeyDown, 184 // The note is currently playing 185 PlayingKeyDown, 186 // We just released the key 187 KeyUp, 188 // The note is being released, e.g. a release sample is playing 189 PlayingKeyUp, 190 // The note is done playing, you can delete this note now 191 Completed 192 } ; 193 194 195 196 197 // Corresponds to a certain midi note pressed, but may contain multiple samples 198 class GigNote 199 { 200 public: 201 int midiNote; 202 int velocity; 203 bool release; // Whether to trigger a release sample on key up 204 bool isRelease; // Whether this is a release sample, changes when we delete it 205 GigState state; 206 float frequency; 207 QList<GigSample> samples; 208 209 // Used to determine which note should be released on key up 210 // 211 // Note: if accessing the data, be careful not to access it after the key 212 // has been released since that's when it is deleted 213 GIGPluginData * handle; 214 GigNote(int midiNote,int velocity,float frequency,GIGPluginData * handle)215 GigNote( int midiNote, int velocity, float frequency, GIGPluginData * handle ) 216 : midiNote( midiNote ), velocity( velocity ), 217 release( false ), isRelease( false ), state( KeyDown ), 218 frequency( frequency ), handle( handle ) 219 { 220 } 221 } ; 222 223 224 225 226 class GigInstrument : public Instrument 227 { 228 Q_OBJECT 229 MM_OPERATORS 230 231 mapPropertyFromModel( int, getBank, setBank, m_bankNum ); 232 mapPropertyFromModel( int, getPatch, setPatch, m_patchNum ); 233 234 public: 235 GigInstrument( InstrumentTrack * _instrument_track ); 236 virtual ~GigInstrument(); 237 238 virtual void play( sampleFrame * _working_buffer ); 239 240 virtual void playNote( NotePlayHandle * _n, 241 sampleFrame * _working_buffer ); 242 virtual void deleteNotePluginData( NotePlayHandle * _n ); 243 244 245 virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); 246 virtual void loadSettings( const QDomElement & _this ); 247 248 virtual void loadFile( const QString & _file ); 249 250 virtual AutomatableModel * childModel( const QString & _modelName ); 251 252 virtual QString nodeName() const; 253 desiredReleaseFrames()254 virtual f_cnt_t desiredReleaseFrames() const 255 { 256 return 0; 257 } 258 flags()259 virtual Flags flags() const 260 { 261 return IsSingleStreamed|IsNotBendable; 262 } 263 264 virtual PluginView * instantiateView( QWidget * _parent ); 265 266 QString getCurrentPatchName(); 267 268 269 void setParameter( const QString & _param, const QString & _value ); 270 271 272 public slots: 273 void openFile( const QString & _gigFile, bool updateTrackName = true ); 274 void updatePatch(); 275 void updateSampleRate(); 276 277 278 private: 279 // The GIG file and instrument we're using 280 GigInstance * m_instance; 281 gig::Instrument * m_instrument; 282 283 // Part of the UI 284 QString m_filename; 285 286 LcdSpinBoxModel m_bankNum; 287 LcdSpinBoxModel m_patchNum; 288 289 FloatModel m_gain; 290 291 // Locking for the data 292 QMutex m_synthMutex; 293 QMutex m_notesMutex; 294 295 // Used for resampling 296 int m_interpolation; 297 298 // List of all the currently playing notes 299 QList<GigNote> m_notes; 300 301 // Used when determining which samples to use 302 uint32_t m_RandomSeed; 303 float m_currentKeyDimension; 304 305 private: 306 // Delete the current GIG instance if one is open 307 void freeInstance(); 308 309 // Open the instrument in the currently-open GIG file 310 void getInstrument(); 311 312 // Create "dimension" to select desired samples from GIG file based on 313 // parameters such as velocity 314 Dimension getDimensions( gig::Region * pRegion, int velocity, bool release ); 315 316 // Load sample data from the Gig file, looping the sample where needed 317 void loadSample( GigSample& sample, sampleFrame* sampleData, f_cnt_t samples ); 318 f_cnt_t getLoopedIndex( f_cnt_t index, f_cnt_t startf, f_cnt_t endf ) const; 319 f_cnt_t getPingPongIndex( f_cnt_t index, f_cnt_t startf, f_cnt_t endf ) const; 320 321 // Add the desired samples to the note, either normal samples or release 322 // samples 323 void addSamples( GigNote & gignote, bool wantReleaseSample ); 324 325 friend class GigInstrumentView; 326 327 signals: 328 void fileLoading(); 329 void fileChanged(); 330 void patchChanged(); 331 332 } ; 333 334 335 336 337 class GigInstrumentView : public InstrumentView 338 { 339 Q_OBJECT 340 public: 341 GigInstrumentView( Instrument * _instrument, 342 QWidget * _parent ); 343 virtual ~GigInstrumentView(); 344 345 private: 346 virtual void modelChanged(); 347 348 PixmapButton * m_fileDialogButton; 349 PixmapButton * m_patchDialogButton; 350 351 LcdSpinBox * m_bankNumLcd; 352 LcdSpinBox * m_patchNumLcd; 353 354 QLabel * m_filenameLabel; 355 QLabel * m_patchLabel; 356 357 Knob * m_gainKnob; 358 359 static PatchesDialog * s_patchDialog; 360 361 protected slots: 362 void invalidateFile(); 363 void showFileDialog(); 364 void showPatchDialog(); 365 void updateFilename(); 366 void updatePatchName(); 367 } ; 368 369 370 #endif 371