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