1 /*************************************************************************** 2 * * 3 * LinuxSampler - modular, streaming capable sampler * 4 * * 5 * Copyright (C) 2003 - 2009 Christian Schoenebeck * 6 * Copyright (C) 2009 - 2013 Grigor Iliev * 7 * * 8 * This program is free software; you can redistribute it and/or modify * 9 * it under the terms of the GNU General Public License as published by * 10 * the Free Software Foundation; either version 2 of the License, or * 11 * (at your option) any later version. * 12 * * 13 * This program is distributed in the hope that it will be useful, * 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 16 * GNU General Public License for more details. * 17 * * 18 * You should have received a copy of the GNU General Public License * 19 * along with this program; if not, write to the Free Software * 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 21 * MA 02111-1307 USA * 22 ***************************************************************************/ 23 24 #ifndef __LS_SAMPLEFILE_H__ 25 #define __LS_SAMPLEFILE_H__ 26 27 #include "Sample.h" 28 29 #include <sndfile.h> 30 #include "../../common/global.h" 31 32 namespace LinuxSampler { 33 class SampleFile : public Sample { 34 public: 35 SampleFile(String File, bool DontClose = false); 36 virtual ~SampleFile(); 37 GetFile()38 String GetFile() { return File; } 39 GetName()40 virtual String GetName() { return File; } GetSampleRate()41 virtual int GetSampleRate() { return SampleRate; } GetChannelCount()42 virtual int GetChannelCount() { return ChannelCount; } GetTotalFrameCount()43 virtual long GetTotalFrameCount() { return TotalFrameCount; } GetFrameSize()44 virtual int GetFrameSize() { return FrameSize; } GetLoops()45 virtual int GetLoops() { return Loops; } GetLoopStart()46 virtual uint GetLoopStart() { return LoopStart; } GetLoopEnd()47 virtual uint GetLoopEnd() { return LoopEnd; } 48 49 virtual buffer_t LoadSampleData(); 50 virtual buffer_t LoadSampleData(unsigned long FrameCount); 51 virtual buffer_t LoadSampleDataWithNullSamplesExtension(uint NullFrameCount); 52 virtual buffer_t LoadSampleDataWithNullSamplesExtension(unsigned long FrameCount, uint NullFramesCount); 53 virtual void ReleaseSampleData(); 54 virtual buffer_t GetCache(); 55 virtual long Read(void* pBuffer, unsigned long FrameCount); 56 57 virtual unsigned long ReadAndLoop ( 58 void* pBuffer, 59 unsigned long FrameCount, 60 PlaybackState* pPlaybackState 61 ); 62 63 virtual long SetPos(unsigned long FrameOffset); 64 virtual long GetPos(); 65 66 void Open(); 67 void Close(); 68 69 private: 70 String File; 71 int SampleRate; 72 int ChannelCount; 73 int Format; 74 int FrameSize; ///< In bytes 75 long TotalFrameCount; 76 int Loops; 77 uint LoopStart; 78 uint LoopEnd; 79 80 SNDFILE* pSndFile; 81 82 buffer_t RAMCache; ///< Buffers samples (already uncompressed) in RAM. 83 84 int* pConvertBuffer; 85 86 long SetPos(unsigned long FrameCount, int Whence); 87 }; 88 89 template <class R> 90 class SampleFileBase : public SampleFile { 91 public: SampleFile(File,DontClose)92 SampleFileBase(String File, bool DontClose = false) : SampleFile(File, DontClose) { } ~SampleFileBase()93 virtual ~SampleFileBase() { } 94 95 96 97 /** 98 * Reads \a SampleCount number of sample points from the position stored 99 * in \a pPlaybackState into the buffer pointed by \a pBuffer and moves 100 * the position within the sample respectively, this method honors the 101 * looping informations of the sample (if any). Use this 102 * method if you don't want to load the sample into RAM, thus for disk 103 * streaming. All this methods needs to know to proceed with streaming 104 * for the next time you call this method is stored in \a pPlaybackState. 105 * You have to allocate and initialize the playback_state_t structure by 106 * yourself before you use it to stream a sample: 107 * @code 108 * PlaybackState playbackstate; 109 * playbackstate.position = 0; 110 * playbackstate.reverse = false; 111 * playbackstate.loop_cycles_left = pSample->LoopPlayCount; 112 * @endcode 113 * You don't have to take care of things like if there is actually a loop 114 * defined or if the current read position is located within a loop area. 115 * The method already handles such cases by itself. 116 * 117 * @param pBuffer destination buffer 118 * @param FrameCount number of sample points to read 119 * @param pPlaybackState will be used to store and reload the playback 120 * state for the next ReadAndLoop() call 121 * @returns number of successfully read sample points 122 */ ReadAndLoop(void * pBuffer,unsigned long FrameCount,PlaybackState * pPlaybackState,R * pRegion)123 unsigned long ReadAndLoop ( 124 void* pBuffer, 125 unsigned long FrameCount, 126 PlaybackState* pPlaybackState, 127 R* pRegion 128 ) { 129 // TODO: startAddrsCoarseOffset, endAddrsCoarseOffset 130 unsigned long samplestoread = FrameCount, totalreadsamples = 0, readsamples, samplestoloopend; 131 uint8_t* pDst = (uint8_t*) pBuffer; 132 SetPos(pPlaybackState->position); 133 if (pRegion->HasLoop()) { 134 do { 135 if (GetPos() > pRegion->GetLoopEnd()) SetPos(pRegion->GetLoopStart()); 136 samplestoloopend = pRegion->GetLoopEnd() - GetPos(); 137 readsamples = Read(&pDst[totalreadsamples * GetFrameSize()], Min(samplestoread, samplestoloopend)); 138 samplestoread -= readsamples; 139 totalreadsamples += readsamples; 140 if (readsamples == samplestoloopend) { 141 SetPos(pRegion->GetLoopStart()); 142 } 143 } while (samplestoread && readsamples); 144 } else { 145 totalreadsamples = Read(pBuffer, FrameCount); 146 } 147 148 pPlaybackState->position = GetPos(); 149 150 return totalreadsamples; 151 } 152 153 protected: Min(long A,long B)154 inline long Min(long A, long B) { return (A > B) ? B : A; } 155 }; 156 } // namespace LinuxSampler 157 158 #endif // __LS_SAMPLEFILE_H__ 159