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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2399 - (show annotations) (download)
Sun Jan 13 17:22:23 2013 UTC (11 years, 3 months ago) by persson
File size: 10432 byte(s)
* sfz engine: added FLAC support (#191)

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

  ViewVC Help
Powered by ViewVC