/[svn]/linuxsampler/trunk/src/engines/common/SampleFile.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/common/SampleFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2674 - (hide annotations) (download)
Thu Sep 11 18:22:14 2014 UTC (9 years, 9 months ago) by persson
File size: 10853 byte(s)
* sfz engine: added support for float and 32 bit sample files


1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003 - 2009 Christian Schoenebeck *
6 persson 2674 * Copyright (C) 2009 - 2014 Grigor Iliev *
7 iliev 2012 * *
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     #include "SampleFile.h"
25 persson 2119 #include "../../common/global_private.h"
26 iliev 2012 #include "../../common/Exception.h"
27    
28     #include <cstring>
29    
30 persson 2399 #define CONVERT_BUFFER_SIZE 4096
31    
32 iliev 2012 namespace LinuxSampler {
33     #if CONFIG_DEVMODE
34     int SampleFile_OpenFilesCount = 0;
35     #endif
36    
37     SampleFile::SampleFile(String File, bool DontClose) {
38     this->File = File;
39     this->pSndFile = NULL;
40 persson 2399 pConvertBuffer = NULL;
41 iliev 2012
42     SF_INFO sfInfo;
43     sfInfo.format = 0;
44     pSndFile = sf_open(File.c_str(), SFM_READ, &sfInfo);
45     if(pSndFile == NULL) throw Exception(File + ": Can't get sample info: " + String(sf_strerror (NULL)));
46     #if CONFIG_DEVMODE
47     std::cout << "Number of opened sample files: " << ++SampleFile_OpenFilesCount << std::endl;
48     #endif
49     SampleRate = sfInfo.samplerate;
50     ChannelCount = sfInfo.channels;
51     Format = sfInfo.format;
52    
53 persson 2119 switch(Format & SF_FORMAT_SUBMASK) {
54 iliev 2012 case SF_FORMAT_PCM_S8:
55     case SF_FORMAT_PCM_U8:
56 iliev 2019 case SF_FORMAT_DPCM_8:
57     FrameSize = ChannelCount;
58     break;
59 iliev 2012 case SF_FORMAT_PCM_16:
60     case SF_FORMAT_DPCM_16:
61 iliev 2019 FrameSize = 2 * ChannelCount;
62 iliev 2012 break;
63 iliev 2019 case SF_FORMAT_PCM_24:
64     case SF_FORMAT_DWVW_24:
65 persson 2674 case SF_FORMAT_PCM_32:
66     case SF_FORMAT_FLOAT:
67 iliev 2019 FrameSize = 3 * ChannelCount;
68     break;
69 iliev 2012 default:
70 iliev 2019 FrameSize = 2 * ChannelCount;
71 iliev 2012 }
72     TotalFrameCount = sfInfo.frames;
73    
74 persson 2167 Loops = 0;
75     LoopStart = 0;
76     LoopEnd = 0;
77     SF_INSTRUMENT instrument;
78     if (sf_command(pSndFile, SFC_GET_INSTRUMENT,
79     &instrument, sizeof(instrument)) != SF_FALSE) {
80     // TODO: instrument.basenote
81     #if HAVE_SF_INSTRUMENT_LOOPS
82     if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
83     Loops = 1;
84     LoopStart = instrument.loops[0].start;
85     LoopEnd = instrument.loops[0].end;
86     }
87     #endif
88     }
89 iliev 2012 if(!DontClose) Close();
90 persson 2399
91 persson 2674 if (FrameSize == 3 * ChannelCount && (
92 persson 2399 #if HAVE_DECL_SF_FORMAT_FLAC
93 persson 2674 (Format & SF_FORMAT_TYPEMASK) == SF_FORMAT_FLAC ||
94     #endif
95     (Format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ||
96     (Format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_32)) {
97 persson 2399 pConvertBuffer = new int[CONVERT_BUFFER_SIZE];
98     }
99 iliev 2012 }
100    
101     SampleFile::~SampleFile() {
102     Close();
103 persson 2058 ReleaseSampleData();
104 persson 2399 delete[] pConvertBuffer;
105 iliev 2012 }
106    
107     void SampleFile::Open() {
108     if(pSndFile) return; // Already opened
109     SF_INFO sfInfo;
110     sfInfo.format = 0;
111     pSndFile = sf_open(File.c_str(), SFM_READ, &sfInfo);
112     if(pSndFile == NULL) throw Exception(File + ": Can't load sample");
113     #if CONFIG_DEVMODE
114     std::cout << "Number of opened sample files: " << ++SampleFile_OpenFilesCount << std::endl;
115     #endif
116     }
117    
118     void SampleFile::Close() {
119     if(pSndFile == NULL) return;
120     if(sf_close(pSndFile)) std::cerr << "Sample::Close() " << "Failed to close " << File << std::endl;
121     pSndFile = NULL;
122     #if CONFIG_DEVMODE
123     std::cout << "Number of opened sample files: " << --SampleFile_OpenFilesCount << std::endl;
124     #endif
125     }
126    
127     long SampleFile::SetPos(unsigned long FrameOffset) {
128     return SetPos(FrameOffset, SEEK_SET);
129     }
130    
131     long SampleFile::SetPos(unsigned long FrameCount, int Whence) {
132     if(pSndFile == NULL) {
133     std::cerr << "Sample::SetPos() " << File << " not opened" << std::endl;
134     return -1;
135     }
136    
137     return sf_seek(pSndFile, FrameCount, Whence);
138     }
139    
140     long SampleFile::GetPos() {
141     if(pSndFile == NULL) {
142     std::cerr << "Sample::GetPos() " << File << " not opened" << std::endl;
143     return -1;
144     }
145    
146     return sf_seek(pSndFile, 0, SEEK_CUR);
147     }
148    
149     Sample::buffer_t SampleFile::LoadSampleData() {
150 iliev 2234 return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), 0); // 0 amount of NullSamples
151 iliev 2012 }
152    
153     Sample::buffer_t SampleFile::LoadSampleData(unsigned long FrameCount) {
154     return LoadSampleDataWithNullSamplesExtension(FrameCount, 0); // 0 amount of NullSamples
155     }
156    
157     Sample::buffer_t SampleFile::LoadSampleDataWithNullSamplesExtension(uint NullFrameCount) {
158 iliev 2234 return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), NullFrameCount);
159 iliev 2012 }
160    
161     Sample::buffer_t SampleFile::LoadSampleDataWithNullSamplesExtension(unsigned long FrameCount, uint NullFramesCount) {
162     Open();
163 iliev 2234 if (FrameCount > GetTotalFrameCount()) FrameCount = GetTotalFrameCount();
164 iliev 2216
165 iliev 2234 if (Offset > MaxOffset && FrameCount < GetTotalFrameCount()) {
166     FrameCount = FrameCount + Offset > GetTotalFrameCount() ? GetTotalFrameCount() - Offset : FrameCount;
167 iliev 2216 // Offset the RAM cache
168     RAMCacheOffset = Offset;
169     }
170 iliev 2012 if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
171     unsigned long allocationsize = (FrameCount + NullFramesCount) * this->FrameSize;
172 iliev 2216 SetPos(RAMCacheOffset, SEEK_SET); // reset read position to playback start point
173 iliev 2012 RAMCache.pStart = new int8_t[allocationsize];
174    
175     RAMCache.Size = Read(RAMCache.pStart, FrameCount) * this->FrameSize;
176     RAMCache.NullExtensionSize = allocationsize - RAMCache.Size;
177     // fill the remaining buffer space with silence samples
178     memset((int8_t*)RAMCache.pStart + RAMCache.Size, 0, RAMCache.NullExtensionSize);
179     Close();
180     return GetCache();
181     }
182    
183     long SampleFile::Read(void* pBuffer, unsigned long FrameCount) {
184     Open();
185 iliev 2234
186     if (GetPos() + FrameCount > GetTotalFrameCount()) FrameCount = GetTotalFrameCount() - GetPos(); // For the cases where a different sample end is specified (not the end of the file)
187 persson 2119
188 persson 2399 // ogg and flac files must be read with sf_readf, not
189     // sf_read_raw. On big endian machines, sf_readf_short is also
190     // used for 16 bit wav files, to get automatic endian
191     // conversion (for 24 bit samples this is handled in
192     // Synthesize::GetSample instead).
193 persson 2119
194 persson 2399 #if WORDS_BIGENDIAN || HAVE_DECL_SF_FORMAT_VORBIS || HAVE_DECL_SF_FORMAT_FLAC
195 persson 2119 if (
196     #if WORDS_BIGENDIAN
197     FrameSize == 2 * ChannelCount
198     #else
199 persson 2399 #if HAVE_DECL_SF_FORMAT_VORBIS
200     ((Format & SF_FORMAT_SUBMASK) == SF_FORMAT_VORBIS)
201     #if HAVE_DECL_SF_FORMAT_FLAC
202     ||
203 persson 2119 #endif
204 persson 2399 #endif
205     #if HAVE_DECL_SF_FORMAT_FLAC
206     (FrameSize == 2 * ChannelCount &&
207     (Format & SF_FORMAT_TYPEMASK) == SF_FORMAT_FLAC)
208     #endif
209     #endif
210 persson 2119 ) {
211     return sf_readf_short(pSndFile, static_cast<short*>(pBuffer), FrameCount);
212 persson 2674 } else if (FrameSize == 3 * ChannelCount && (
213 persson 2399 #if HAVE_DECL_SF_FORMAT_FLAC
214 persson 2674 (Format & SF_FORMAT_TYPEMASK) == SF_FORMAT_FLAC ||
215     #endif
216     (Format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ||
217     (Format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_32)) {
218 persson 2399 // 24 bit flac needs to be converted from the 32 bit
219 persson 2674 // integers returned by libsndfile. Float and 32 bit pcm
220     // are treated in the same way.
221 persson 2399 int j = 0;
222     sf_count_t count = FrameCount;
223     const sf_count_t bufsize = CONVERT_BUFFER_SIZE / ChannelCount;
224     unsigned char* const dst = static_cast<unsigned char*>(pBuffer);
225     while (count > 0) {
226     int n = sf_readf_int(pSndFile, pConvertBuffer, std::min(count, bufsize));
227     if (n <= 0) break;
228     for (int i = 0 ; i < n * ChannelCount ; i++) {
229     dst[j++] = pConvertBuffer[i] >> 8;
230     dst[j++] = pConvertBuffer[i] >> 16;
231     dst[j++] = pConvertBuffer[i] >> 24;
232     }
233     count -= n;
234     }
235     return FrameCount - count;
236 persson 2119 } else
237     #endif
238     {
239     int bytes = sf_read_raw(pSndFile, pBuffer, FrameCount * GetFrameSize());
240     return bytes / GetFrameSize();
241     }
242 iliev 2012 }
243    
244     unsigned long SampleFile::ReadAndLoop (
245     void* pBuffer,
246     unsigned long FrameCount,
247     PlaybackState* pPlaybackState
248     ) {
249     // TODO:
250     SetPos(pPlaybackState->position);
251 iliev 2018 unsigned long count = Read(pBuffer, FrameCount);
252 iliev 2012 pPlaybackState->position = GetPos();
253 iliev 2018 return count;
254 iliev 2012 }
255    
256     void SampleFile::ReleaseSampleData() {
257     if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
258     RAMCache.pStart = NULL;
259     RAMCache.Size = 0;
260     RAMCache.NullExtensionSize = 0;
261     }
262    
263     Sample::buffer_t SampleFile::GetCache() {
264     // return a copy of the buffer_t structure
265     buffer_t result;
266     result.Size = this->RAMCache.Size;
267     result.pStart = this->RAMCache.pStart;
268     result.NullExtensionSize = this->RAMCache.NullExtensionSize;
269     return result;
270     }
271     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC