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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 549 - (show annotations) (download)
Mon May 16 18:40:45 2005 UTC (18 years, 10 months ago) by schoenebeck
File size: 15064 byte(s)
* src/gigextract.cpp: show also version of libsndfile or build version of
  libaudiofile when using the -v switch

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

  ViewVC Help
Powered by ViewVC