/[svn]/libgig/trunk/src/gigextract.cpp
ViewVC logotype

Contents of /libgig/trunk/src/gigextract.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 365 - (show annotations) (download)
Thu Feb 10 19:16:31 2005 UTC (19 years, 1 month ago) by persson
File size: 13891 byte(s)
* src/gig.cpp, src/gig.h, src/gigextract.cpp: Support for compressed
  mono samples. Experimental support for compressed 24 bit
  samples. Fixes for decompression on big-endian CPUs. Fix for bug
  that truncated end of compressed samples.

1 /***************************************************************************
2 * *
3 * libgig - C++ cross-platform Gigasampler format file loader library *
4 * *
5 * Copyright (C) 2003, 2004 by Christian Schoenebeck *
6 * <cuse@users.sourceforge.net> *
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 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 // just for testing the disk streaming capability of libgig;
29 // you will also need to set this to 1 at the moment if you want to
30 // extract compressed samples, as I haven't implemented the
31 // decompression algorithm in gig::Sample::LoadSampleData() yet
32 #define USE_DISK_STREAMING 1
33
34 // only when USE_DISK_STREAMING is set to 1:
35 // just for testing the disk stream capability; with this option set
36 // gigextract will read the samples in smaller pieces, just to stress
37 // gig::Sample::Read() method a bit
38 #define HASHED_READS_TEST 1
39
40 #include <iostream>
41 #include <cstdlib>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <dirent.h>
47 #include <errno.h>
48 #include <dlfcn.h>
49
50 // only libsndfile is available for Windows, so we use that for writing the sound files
51 #ifdef WIN32
52 # define HAVE_SNDFILE 1
53 #endif // WIN32
54
55 // we prefer libsndfile before libaudiofile
56 #if HAVE_SNDFILE
57 # include <sndfile.h>
58 #else
59 # include <audiofile.h>
60 #endif // HAVE_SNDFILE
61
62 #include "gig.h"
63
64 using namespace std;
65
66 typedef map<unsigned int, bool> OrderMap;
67 OrderMap* pOrderedSamples = NULL;
68
69 void PrintUsage();
70 void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered);
71 int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate);
72 string ToString(int i);
73
74 #ifndef HAVE_SNDFILE
75 void* hAFlib; // handle to libaudiofile
76 void openAFlib(void);
77 void closeAFlib(void);
78 // pointers to libaudiofile functions
79 AFfilesetup(*_afNewFileSetup)(void);
80 void(*_afFreeFileSetup)(AFfilesetup);
81 void(*_afInitChannels)(AFfilesetup,int,int);
82 void(*_afInitSampleFormat)(AFfilesetup,int,int,int);
83 void(*_afInitFileFormat)(AFfilesetup,int);
84 void(*_afInitRate)(AFfilesetup,int,double);
85 int(*_afWriteFrames)(AFfilehandle,int,const void*,int);
86 AFfilehandle(*_afOpenFile)(const char*,const char*,AFfilesetup);
87 int(*_afCloseFile)(AFfilehandle file);
88 #endif // !HAVE_SNDFILE
89
90 int main(int argc, char *argv[]) {
91 if (argc < 3) {
92 PrintUsage();
93 return EXIT_FAILURE;
94 }
95 if (argc > 3) { // extracting specific samples
96 pOrderedSamples = new OrderMap;
97 for (int i = 3; i < argc; i++) {
98 unsigned int index = atoi(argv[i]);
99 (*pOrderedSamples)[index] = true;
100 }
101 }
102 FILE* hFile = fopen(argv[1], "r");
103 if (!hFile) {
104 cout << "Invalid input file argument!" << endl;
105 return EXIT_FAILURE;
106 }
107 fclose(hFile);
108 DIR* dir = opendir(argv[2]);
109 if (!dir) {
110 cout << "Unable to open DESTDIR: ";
111 switch (errno) {
112 case EACCES: cout << "Permission denied." << endl;
113 break;
114 case EMFILE: cout << "Too many file descriptors in use by process." << endl;
115 break;
116 case ENFILE: cout << "Too many files are currently open in the system." << endl;
117 break;
118 case ENOENT: cout << "Directory does not exist, or name is an empty string." << endl;
119 break;
120 case ENOMEM: cout << "Insufficient memory to complete the operation." << endl;
121 break;
122 case ENOTDIR: cout << "Is not a directory." << endl;
123 break;
124 default: cout << "Unknown error" << endl;
125 }
126 return EXIT_FAILURE;
127 }
128 if (dir) closedir(dir);
129 try {
130 RIFF::File* riff = new RIFF::File(argv[1]);
131 gig::File* gig = new gig::File(riff);
132 cout << "Extracting samples from \"" << argv[1] << "\" to directory \"" << argv[2] << "\"." << endl << flush;
133 ExtractSamples(gig, argv[2], pOrderedSamples);
134 cout << "Extraction finished." << endl << flush;
135 delete gig;
136 delete riff;
137 if (pOrderedSamples) delete pOrderedSamples;
138 }
139 catch (RIFF::Exception e) {
140 e.PrintMessage();
141 return EXIT_FAILURE;
142 }
143 catch (...) {
144 cout << "Unknown exception while trying to parse file." << endl;
145 return EXIT_FAILURE;
146 }
147
148 return EXIT_SUCCESS;
149 }
150
151 void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered) {
152 #ifndef HAVE_SNDFILE
153 hAFlib = NULL;
154 openAFlib();
155 #endif // !HAVE_SNDFILE
156 uint8_t* pWave = NULL;
157 long BufferSize = 0;
158 int samples = 0;
159 cout << "Seeking for available samples..." << flush;
160 gig::Sample* pSample = gig->GetFirstSample();
161 cout << "OK" << endl << flush;
162 while (pSample) {
163 samples++;
164 if (ordered) {
165 if ((*ordered)[samples] == false) {
166 pSample = gig->GetNextSample();
167 continue;
168 }
169 }
170 string name = pSample->pInfo->Name;
171 string filename = destdir;
172 if (filename[filename.size() - 1] != '/') filename += "/";
173 filename += ToString(samples);
174 filename += "_";
175 if (name == "") {
176 name = "(NO NAME)";
177 filename += "NONAME";
178 }
179 else {
180 filename += name;
181 name.insert(0, "\"");
182 name += "\"";
183 }
184 filename += ".wav";
185 if (pSample->Compressed) cout << "Decompressing ";
186 else cout << "Extracting ";
187 cout << "Sample " << samples << ") " << name << " (" << pSample->BitDepth <<"Bits, " << pSample->SamplesPerSecond << "Hz, " << pSample->Channels << " Channels, " << pSample->SamplesTotal << " Samples)..." << flush;
188
189
190 #if USE_DISK_STREAMING
191 long neededsize = (pSample->Compressed) ? 10485760 /* 10 MB buffer */
192 : pSample->SamplesTotal * pSample->FrameSize;
193 if (BufferSize < neededsize) {
194 if (pWave) delete[] pWave;
195 pWave = new uint8_t[neededsize];
196 BufferSize = neededsize;
197 }
198 # if HASHED_READS_TEST
199 unsigned long readsamples = 0,
200 readinthisrun = 0,
201 samplepiecesize = 2000;
202 uint8_t* pSamplePiece = pWave;
203 do { // we read the sample in small pieces and increment the size with each run just to test streaming capability
204 readinthisrun = pSample->Read(pSamplePiece, ++samplepiecesize);
205 // 24 bit is truncated to 16 by Sample::Read at the moment
206 pSamplePiece += readinthisrun * (2 * pSample->Channels); // readinthisrun * pSample->FrameSize;
207 readsamples += readinthisrun;
208 } while (readinthisrun == samplepiecesize);
209
210 if (pSample->Compressed) { // hack
211 pSample->SamplesTotal = readsamples;
212 pSample->BitDepth = 16;
213 }
214 # else // read in one piece
215 if (pSample->Compressed) {
216 pSample->SamplesTotal = pSample->Read(pWave, 10485760 >> 2); // assumes 16 bit stereo
217 }
218 else {
219 pSample->Read(pWave, pSample->SamplesTotal);
220 }
221 # endif // HASHED_READS_TEST
222 #else // no disk streaming
223 if (pSample->Compressed) {
224 cout << "Sorry, sample is compressed and Sample::LoadSampleData() has no decompression routine yet! - Solution: set USE_DISK_STREAMING in gigextract.cpp (line 29) to 1 and recompile!" << endl;
225 }
226 else pWave = (uint8_t*) pSample->LoadSampleData(); // load wave into RAM
227 #endif // USE_DISK_STREAMING
228 if (pWave) {
229 int res = writeWav(filename.c_str(),
230 pWave,
231 pSample->SamplesTotal,
232 pSample->Channels,
233 pSample->BitDepth,
234 pSample->SamplesPerSecond);
235 if (res < 0) cout << "Couldn't write sample data." << endl;
236 else cout << "ok" << endl;
237 pSample->ReleaseSampleData(); // free wave from RAM
238 }
239 else cout << "Failed to load sample data." << endl;
240
241 pSample = gig->GetNextSample();
242 }
243 if (pWave) delete[] (uint8_t*) pWave;
244 #ifndef HAVE_SNDFILE
245 closeAFlib();
246 #endif // !HAVE_SNDFILE
247 }
248
249 int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
250 #if HAVE_SNDFILE
251 SNDFILE* hfile;
252 SF_INFO sfinfo;
253 int format = SF_FORMAT_WAV;
254 switch (bitdepth) {
255 case 8:
256 format |= SF_FORMAT_PCM_S8;
257 cout << "8 bit" << endl << flush;
258 break;
259 case 16:
260 format |= SF_FORMAT_PCM_16;
261 cout << "16 bit" << endl << flush;
262 break;
263 case 24:
264 format |= SF_FORMAT_PCM_24;
265 cout << "24 bit" << endl << flush;
266 break;
267 case 32:
268 format |= SF_FORMAT_PCM_32;
269 cout << "32 bit" << endl << flush;
270 break;
271 default:
272 cerr << "Error: Bithdepth " << ToString(bitdepth) << " not supported by libsndfile, ignoring sample!\n" << flush;
273 return -1;
274 }
275 memset(&sfinfo, 0, sizeof (sfinfo));
276 sfinfo.samplerate = rate;
277 sfinfo.frames = samplecount;
278 sfinfo.channels = channels;
279 sfinfo.format = format;
280 if (!(hfile = sf_open(filename, SFM_WRITE, &sfinfo))) {
281 cerr << "Error: Unable to open output file \'" << filename << "\'.\n" << flush;
282 return -1;
283 }
284 if (sf_write_short(hfile, (short*)samples, channels * samplecount) != channels * samplecount) {
285 cerr << sf_strerror(hfile) << endl << flush;
286 sf_close(hfile);
287 return -1;
288 }
289 sf_close(hfile);
290 #else
291 AFfilesetup setup = _afNewFileSetup();
292 _afInitFileFormat(setup, AF_FILE_WAVE);
293 _afInitChannels(setup, AF_DEFAULT_TRACK, channels);
294 _afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, bitdepth);
295 _afInitRate(setup, AF_DEFAULT_TRACK, rate);
296 if (setup == AF_NULL_FILESETUP) return -1;
297 AFfilehandle hFile = _afOpenFile(filename, "w", setup);
298 if (hFile == AF_NULL_FILEHANDLE) return -1;
299 if (_afWriteFrames(hFile, AF_DEFAULT_TRACK, samples, samplecount) < 0) return -1;
300 _afCloseFile(hFile);
301 _afFreeFileSetup(setup);
302 #endif // HAVE_SNDFILE
303
304 return 0; // success
305 }
306
307 #ifndef HAVE_SNDFILE
308 void openAFlib() {
309 hAFlib = dlopen("libaudiofile.so", RTLD_NOW);
310 if (!hAFlib) {
311 cout << "Unable to load library libaudiofile.so: " << dlerror() << endl;
312 return;
313 }
314 _afNewFileSetup = (AFfilesetup(*)(void)) dlsym(hAFlib, "afNewFileSetup");
315 _afFreeFileSetup = (void(*)(AFfilesetup)) dlsym(hAFlib, "afFreeFileSetup");
316 _afInitChannels = (void(*)(AFfilesetup,int,int)) dlsym(hAFlib, "afInitChannels");
317 _afInitSampleFormat = (void(*)(AFfilesetup,int,int,int)) dlsym(hAFlib, "afInitSampleFormat");
318 _afInitFileFormat = (void(*)(AFfilesetup,int)) dlsym(hAFlib, "afInitFileFormat");
319 _afInitRate = (void(*)(AFfilesetup,int,double)) dlsym(hAFlib, "afInitRate");
320 _afWriteFrames = (int(*)(AFfilehandle,int,const void*,int)) dlsym(hAFlib, "afWriteFrames");
321 _afOpenFile = (AFfilehandle(*)(const char*,const char*,AFfilesetup)) dlsym(hAFlib, "afOpenFile");
322 _afCloseFile = (int(*)(AFfilehandle file)) dlsym(hAFlib, "afCloseFile");
323 if (dlerror()) cout << "Failed to load function from libaudiofile.so: " << dlerror() << endl;
324 }
325
326 void closeAFlib() {
327 if (hAFlib) dlclose(hAFlib);
328 }
329 #endif // !HAVE_SNDFILE
330
331 void PrintUsage() {
332 cout << "gigextract - extracts samples from a Gigasampler file." << endl;
333 cout << endl;
334 cout << "Usage: gigextract GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl;
335 cout << endl;
336 cout << " GIGFILE Input Gigasampler (.gig) file." << endl;
337 cout << endl;
338 cout << " DESTDIR Destination directory where all .wav files will be written to." << endl;
339 cout << endl;
340 cout << " SAMPLENR Index (/indices) of Sample(s) which should be extracted." << endl;
341 cout << " If no sample indices are given, all samples will be extracted" << endl;
342 cout << " (use gigdump to look for available samples)." << endl;
343 cout << endl;
344 }
345
346 string ToString(int i) {
347 static char strbuf[1024];
348 sprintf(strbuf,"%d",i);
349 string s = strbuf;
350 return s;
351 }

  ViewVC Help
Powered by ViewVC