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

Annotation of /libgig/trunk/src/tools/gigextract.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1063 - (hide annotations) (download)
Sat Mar 3 21:45:25 2007 UTC (17 years, 1 month ago) by schoenebeck
Original Path: libgig/trunk/src/gigextract.cpp
File size: 16898 byte(s)
* fixed libgig's Dev-C++ project file to produce an actually working
  Windows DLL file (mandatory symbols were not exported so far)
* fixed native Windows implementation of RIFF::File::__GetFileSize() to
  work with younger versions than XP as well
* added Dev-C++ project files for the demo / example applications as well
* added instructions in README for how to compile libgig and its tools for
  Windows

1 schoenebeck 2 /***************************************************************************
2     * *
3 schoenebeck 933 * libgig - C++ cross-platform Gigasampler format file access library *
4 schoenebeck 2 * *
5 schoenebeck 1063 * Copyright (C) 2003-2007 by Christian Schoenebeck *
6 schoenebeck 518 * <cuse@users.sourceforge.net> *
7 schoenebeck 2 * *
8 schoenebeck 933 * This program is part of libgig. *
9     * *
10 schoenebeck 2 * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 2 of the License, or *
13     * (at your option) any later version. *
14     * *
15     * This program is distributed in the hope that it will be useful, *
16     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18     * GNU General Public License for more details. *
19     * *
20     * You should have received a copy of the GNU General Public License *
21     * along with this program; if not, write to the Free Software *
22     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
23     * MA 02111-1307 USA *
24     ***************************************************************************/
25    
26     #ifdef HAVE_CONFIG_H
27     #include <config.h>
28     #endif
29    
30     // just for testing the disk streaming capability of libgig;
31     // you will also need to set this to 1 at the moment if you want to
32     // extract compressed samples, as I haven't implemented the
33     // decompression algorithm in gig::Sample::LoadSampleData() yet
34     #define USE_DISK_STREAMING 1
35    
36     // only when USE_DISK_STREAMING is set to 1:
37     // just for testing the disk stream capability; with this option set
38     // gigextract will read the samples in smaller pieces, just to stress
39     // gig::Sample::Read() method a bit
40     #define HASHED_READS_TEST 1
41    
42     #include <iostream>
43     #include <cstdlib>
44 schoenebeck 220 #include <string.h>
45 schoenebeck 518 #include <string>
46 schoenebeck 2 #include <stdlib.h>
47     #include <sys/types.h>
48     #include <sys/stat.h>
49     #include <dirent.h>
50     #include <errno.h>
51 schoenebeck 220
52 schoenebeck 1063 #include "gig.h"
53    
54     #if POSIX
55     # include <dlfcn.h>
56     #endif
57    
58 schoenebeck 220 // only libsndfile is available for Windows, so we use that for writing the sound files
59     #ifdef WIN32
60     # define HAVE_SNDFILE 1
61     #endif // WIN32
62    
63 schoenebeck 608 // abort compilation here if neither libsndfile nor libaudiofile are available
64     #if !HAVE_SNDFILE && !HAVE_AUDIOFILE
65     # error "Neither libsndfile nor libaudiofile seem to be available!"
66     # error "(HAVE_SNDFILE and HAVE_AUDIOFILE are both false)"
67     #endif
68    
69 schoenebeck 220 // we prefer libsndfile before libaudiofile
70     #if HAVE_SNDFILE
71     # include <sndfile.h>
72     #else
73     # include <audiofile.h>
74     #endif // HAVE_SNDFILE
75    
76 schoenebeck 2 using namespace std;
77    
78     typedef map<unsigned int, bool> OrderMap;
79     OrderMap* pOrderedSamples = NULL;
80    
81 schoenebeck 518 string Revision();
82     void PrintVersion();
83 schoenebeck 2 void PrintUsage();
84     void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered);
85     int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate);
86 schoenebeck 220 string ToString(int i);
87    
88 schoenebeck 608 #if !HAVE_SNDFILE // use libaudiofile
89 schoenebeck 2 void* hAFlib; // handle to libaudiofile
90     void openAFlib(void);
91     void closeAFlib(void);
92     // pointers to libaudiofile functions
93     AFfilesetup(*_afNewFileSetup)(void);
94     void(*_afFreeFileSetup)(AFfilesetup);
95     void(*_afInitChannels)(AFfilesetup,int,int);
96     void(*_afInitSampleFormat)(AFfilesetup,int,int,int);
97     void(*_afInitFileFormat)(AFfilesetup,int);
98     void(*_afInitRate)(AFfilesetup,int,double);
99     int(*_afWriteFrames)(AFfilehandle,int,const void*,int);
100     AFfilehandle(*_afOpenFile)(const char*,const char*,AFfilesetup);
101     int(*_afCloseFile)(AFfilehandle file);
102 schoenebeck 220 #endif // !HAVE_SNDFILE
103 schoenebeck 2
104     int main(int argc, char *argv[]) {
105 schoenebeck 518 if (argc >= 2) {
106     if (argv[1][0] == '-') {
107     switch (argv[1][1]) {
108     case 'v':
109     PrintVersion();
110     return EXIT_SUCCESS;
111     }
112     }
113     }
114 schoenebeck 2 if (argc < 3) {
115     PrintUsage();
116     return EXIT_FAILURE;
117     }
118     if (argc > 3) { // extracting specific samples
119     pOrderedSamples = new OrderMap;
120     for (int i = 3; i < argc; i++) {
121     unsigned int index = atoi(argv[i]);
122     (*pOrderedSamples)[index] = true;
123     }
124     }
125     FILE* hFile = fopen(argv[1], "r");
126     if (!hFile) {
127     cout << "Invalid input file argument!" << endl;
128     return EXIT_FAILURE;
129     }
130     fclose(hFile);
131     DIR* dir = opendir(argv[2]);
132     if (!dir) {
133     cout << "Unable to open DESTDIR: ";
134     switch (errno) {
135     case EACCES: cout << "Permission denied." << endl;
136     break;
137     case EMFILE: cout << "Too many file descriptors in use by process." << endl;
138     break;
139     case ENFILE: cout << "Too many files are currently open in the system." << endl;
140     break;
141     case ENOENT: cout << "Directory does not exist, or name is an empty string." << endl;
142     break;
143     case ENOMEM: cout << "Insufficient memory to complete the operation." << endl;
144     break;
145     case ENOTDIR: cout << "Is not a directory." << endl;
146     break;
147     default: cout << "Unknown error" << endl;
148     }
149     return EXIT_FAILURE;
150     }
151     if (dir) closedir(dir);
152     try {
153     RIFF::File* riff = new RIFF::File(argv[1]);
154     gig::File* gig = new gig::File(riff);
155     cout << "Extracting samples from \"" << argv[1] << "\" to directory \"" << argv[2] << "\"." << endl << flush;
156     ExtractSamples(gig, argv[2], pOrderedSamples);
157     cout << "Extraction finished." << endl << flush;
158     delete gig;
159     delete riff;
160     if (pOrderedSamples) delete pOrderedSamples;
161     }
162     catch (RIFF::Exception e) {
163     e.PrintMessage();
164     return EXIT_FAILURE;
165     }
166     catch (...) {
167     cout << "Unknown exception while trying to parse file." << endl;
168     return EXIT_FAILURE;
169     }
170    
171     return EXIT_SUCCESS;
172     }
173    
174     void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered) {
175 schoenebeck 608 #if !HAVE_SNDFILE // use libaudiofile
176 schoenebeck 2 hAFlib = NULL;
177     openAFlib();
178 schoenebeck 220 #endif // !HAVE_SNDFILE
179 schoenebeck 2 uint8_t* pWave = NULL;
180 persson 902 int* pIntWave = NULL;
181 schoenebeck 2 long BufferSize = 0;
182     int samples = 0;
183 persson 902 gig::buffer_t decompressionBuffer;
184     decompressionBuffer.Size = 0;
185     unsigned long decompressionBufferSize = 0;
186 schoenebeck 2 cout << "Seeking for available samples..." << flush;
187     gig::Sample* pSample = gig->GetFirstSample();
188     cout << "OK" << endl << flush;
189     while (pSample) {
190     samples++;
191     if (ordered) {
192     if ((*ordered)[samples] == false) {
193     pSample = gig->GetNextSample();
194     continue;
195     }
196     }
197     string name = pSample->pInfo->Name;
198     string filename = destdir;
199     if (filename[filename.size() - 1] != '/') filename += "/";
200     filename += ToString(samples);
201     filename += "_";
202     if (name == "") {
203     name = "(NO NAME)";
204     filename += "NONAME";
205     }
206     else {
207     filename += name;
208     name.insert(0, "\"");
209     name += "\"";
210     }
211     filename += ".wav";
212     if (pSample->Compressed) cout << "Decompressing ";
213     else cout << "Extracting ";
214     cout << "Sample " << samples << ") " << name << " (" << pSample->BitDepth <<"Bits, " << pSample->SamplesPerSecond << "Hz, " << pSample->Channels << " Channels, " << pSample->SamplesTotal << " Samples)..." << flush;
215    
216    
217     #if USE_DISK_STREAMING
218 persson 902 long neededsize = pSample->BitDepth == 24 ?
219     pSample->SamplesTotal * pSample->Channels * sizeof(int) :
220     pSample->SamplesTotal * pSample->FrameSize;
221 schoenebeck 2 if (BufferSize < neededsize) {
222     if (pWave) delete[] pWave;
223     pWave = new uint8_t[neededsize];
224     BufferSize = neededsize;
225     }
226 persson 902 pIntWave = (int*)pWave;
227 schoenebeck 2 # if HASHED_READS_TEST
228 persson 902 unsigned long readinthisrun = 0,
229 schoenebeck 2 samplepiecesize = 2000;
230     uint8_t* pSamplePiece = pWave;
231     do { // we read the sample in small pieces and increment the size with each run just to test streaming capability
232     readinthisrun = pSample->Read(pSamplePiece, ++samplepiecesize);
233 persson 902 pSamplePiece += readinthisrun * pSample->FrameSize;
234 schoenebeck 2 } while (readinthisrun == samplepiecesize);
235    
236     # else // read in one piece
237     if (pSample->Compressed) {
238 persson 902 if (decompressionBufferSize < pSample->SamplesTotal) {
239     gig::Sample::DestroyDecompressionBuffer(decompressionBuffer);
240     decompressionBuffer = gig::Sample::CreateDecompressionBuffer(pSample->SamplesTotal);
241     decompressionBufferSize = pSample->SamplesTotal;
242     }
243     pSample->Read(pWave, pSample->SamplesTotal, &decompressionBuffer);
244     } else {
245 schoenebeck 2 pSample->Read(pWave, pSample->SamplesTotal);
246     }
247     # endif // HASHED_READS_TEST
248     #else // no disk streaming
249     if (pSample->Compressed) {
250 persson 902 cout << "Sorry, sample is compressed and Sample::LoadSampleData() only decompresses the beginning of the sample - Solution: set USE_DISK_STREAMING in gigextract.cpp (line 32) to 1 and recompile!" << endl;
251     } else {
252     gig::buffer_t buffer = pSample->LoadSampleData(); // load wave into RAM
253     pWave = static_cast<uint8_t*>(buffer.pStart);
254     if (pSample->BitDepth == 24) {
255     long neededsize = pSample->SamplesTotal * pSample->Channels;
256     if (BufferSize < neededsize) {
257     if (pIntWave) delete[] pIntWave;
258     pIntWave = new int[neededsize];
259     BufferSize = neededsize;
260     }
261     }
262 schoenebeck 2 }
263     #endif // USE_DISK_STREAMING
264     if (pWave) {
265 persson 902
266     // Both libsndfile and libaudiofile uses int for 24 bit
267     // samples. libgig however returns 3 bytes per sample, so
268     // we have to convert the wave data before writing.
269     if (pSample->BitDepth == 24) {
270     int n = pSample->SamplesTotal * pSample->Channels;
271     for (int i = n - 1 ; i >= 0 ; i--) {
272     #if HAVE_SNDFILE
273     pIntWave[i] = pWave[i * 3] << 8 | pWave[i * 3 + 1] << 16 | pWave[i * 3 + 2] << 24;
274     #else
275     pIntWave[i] = pWave[i * 3] | pWave[i * 3 + 1] << 8 | pWave[i * 3 + 2] << 16;
276     #endif
277     }
278     }
279    
280 schoenebeck 2 int res = writeWav(filename.c_str(),
281 persson 902 pSample->BitDepth == 24 ? static_cast<void*>(pIntWave) : pWave,
282 schoenebeck 2 pSample->SamplesTotal,
283     pSample->Channels,
284     pSample->BitDepth,
285     pSample->SamplesPerSecond);
286     if (res < 0) cout << "Couldn't write sample data." << endl;
287     else cout << "ok" << endl;
288     pSample->ReleaseSampleData(); // free wave from RAM
289     }
290     else cout << "Failed to load sample data." << endl;
291    
292     pSample = gig->GetNextSample();
293     }
294 persson 902 gig::Sample::DestroyDecompressionBuffer(decompressionBuffer);
295     #if USE_DISK_STREAMING
296     if (pWave) delete[] pWave;
297     #else
298     if (pIntWave) delete[] pIntWave;
299     #endif
300 schoenebeck 608 #if !HAVE_SNDFILE // use libaudiofile
301 schoenebeck 2 closeAFlib();
302 schoenebeck 220 #endif // !HAVE_SNDFILE
303 schoenebeck 2 }
304    
305     int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
306 schoenebeck 220 #if HAVE_SNDFILE
307     SNDFILE* hfile;
308     SF_INFO sfinfo;
309     int format = SF_FORMAT_WAV;
310     switch (bitdepth) {
311     case 8:
312     format |= SF_FORMAT_PCM_S8;
313     break;
314     case 16:
315     format |= SF_FORMAT_PCM_16;
316     break;
317     case 24:
318     format |= SF_FORMAT_PCM_24;
319     break;
320     case 32:
321     format |= SF_FORMAT_PCM_32;
322     break;
323     default:
324     cerr << "Error: Bithdepth " << ToString(bitdepth) << " not supported by libsndfile, ignoring sample!\n" << flush;
325     return -1;
326     }
327     memset(&sfinfo, 0, sizeof (sfinfo));
328     sfinfo.samplerate = rate;
329     sfinfo.frames = samplecount;
330     sfinfo.channels = channels;
331     sfinfo.format = format;
332     if (!(hfile = sf_open(filename, SFM_WRITE, &sfinfo))) {
333     cerr << "Error: Unable to open output file \'" << filename << "\'.\n" << flush;
334     return -1;
335     }
336 persson 902 sf_count_t res = bitdepth == 24 ?
337     sf_write_int(hfile, static_cast<int*>(samples), channels * samplecount) :
338     sf_write_short(hfile, static_cast<short*>(samples), channels * samplecount);
339     if (res != channels * samplecount) {
340 schoenebeck 220 cerr << sf_strerror(hfile) << endl << flush;
341     sf_close(hfile);
342     return -1;
343     }
344     sf_close(hfile);
345 schoenebeck 608 #else // use libaudiofile
346 schoenebeck 2 AFfilesetup setup = _afNewFileSetup();
347     _afInitFileFormat(setup, AF_FILE_WAVE);
348     _afInitChannels(setup, AF_DEFAULT_TRACK, channels);
349     _afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, bitdepth);
350     _afInitRate(setup, AF_DEFAULT_TRACK, rate);
351     if (setup == AF_NULL_FILESETUP) return -1;
352     AFfilehandle hFile = _afOpenFile(filename, "w", setup);
353     if (hFile == AF_NULL_FILEHANDLE) return -1;
354     if (_afWriteFrames(hFile, AF_DEFAULT_TRACK, samples, samplecount) < 0) return -1;
355     _afCloseFile(hFile);
356     _afFreeFileSetup(setup);
357 schoenebeck 220 #endif // HAVE_SNDFILE
358 schoenebeck 55
359 schoenebeck 220 return 0; // success
360 schoenebeck 2 }
361    
362 schoenebeck 608 #if !HAVE_SNDFILE // use libaudiofile
363 schoenebeck 2 void openAFlib() {
364     hAFlib = dlopen("libaudiofile.so", RTLD_NOW);
365     if (!hAFlib) {
366     cout << "Unable to load library libaudiofile.so: " << dlerror() << endl;
367     return;
368     }
369     _afNewFileSetup = (AFfilesetup(*)(void)) dlsym(hAFlib, "afNewFileSetup");
370     _afFreeFileSetup = (void(*)(AFfilesetup)) dlsym(hAFlib, "afFreeFileSetup");
371     _afInitChannels = (void(*)(AFfilesetup,int,int)) dlsym(hAFlib, "afInitChannels");
372     _afInitSampleFormat = (void(*)(AFfilesetup,int,int,int)) dlsym(hAFlib, "afInitSampleFormat");
373     _afInitFileFormat = (void(*)(AFfilesetup,int)) dlsym(hAFlib, "afInitFileFormat");
374     _afInitRate = (void(*)(AFfilesetup,int,double)) dlsym(hAFlib, "afInitRate");
375     _afWriteFrames = (int(*)(AFfilehandle,int,const void*,int)) dlsym(hAFlib, "afWriteFrames");
376     _afOpenFile = (AFfilehandle(*)(const char*,const char*,AFfilesetup)) dlsym(hAFlib, "afOpenFile");
377     _afCloseFile = (int(*)(AFfilehandle file)) dlsym(hAFlib, "afCloseFile");
378     if (dlerror()) cout << "Failed to load function from libaudiofile.so: " << dlerror() << endl;
379     }
380    
381     void closeAFlib() {
382     if (hAFlib) dlclose(hAFlib);
383     }
384 schoenebeck 220 #endif // !HAVE_SNDFILE
385 schoenebeck 2
386 schoenebeck 518 string Revision() {
387 schoenebeck 1063 string s = "$Revision: 1.10 $";
388 schoenebeck 518 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
389     }
390    
391     void PrintVersion() {
392     cout << "gigextract revision " << Revision() << endl;
393 schoenebeck 549 cout << "using " << gig::libraryName() << " " << gig::libraryVersion();
394     #if HAVE_SNDFILE
395     char versionBuffer[128];
396     sf_command(NULL, SFC_GET_LIB_VERSION, versionBuffer, 128);
397     cout << ", " << versionBuffer;
398 schoenebeck 608 #else // use libaudiofile
399     cout << "\nbuilt against libaudiofile "
400     << LIBAUDIOFILE_MAJOR_VERSION << "." << LIBAUDIOFILE_MINOR_VERSION;
401     # ifdef LIBAUDIOFILE_MICRO_VERSION
402     cout << "." << LIBAUDIOFILE_MICRO_VERSION;
403     # endif // LIBAUDIOFILE_MICRO_VERSION
404 schoenebeck 549 #endif // HAVE_SNDFILE
405     cout << endl;
406 schoenebeck 518 }
407    
408 schoenebeck 2 void PrintUsage() {
409     cout << "gigextract - extracts samples from a Gigasampler file." << endl;
410     cout << endl;
411 schoenebeck 518 cout << "Usage: gigextract [-v] GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl;
412 schoenebeck 2 cout << endl;
413     cout << " GIGFILE Input Gigasampler (.gig) file." << endl;
414     cout << endl;
415     cout << " DESTDIR Destination directory where all .wav files will be written to." << endl;
416     cout << endl;
417     cout << " SAMPLENR Index (/indices) of Sample(s) which should be extracted." << endl;
418     cout << " If no sample indices are given, all samples will be extracted" << endl;
419     cout << " (use gigdump to look for available samples)." << endl;
420     cout << endl;
421 schoenebeck 518 cout << " -v Print version and exit." << endl;
422     cout << endl;
423 schoenebeck 2 }
424    
425     string ToString(int i) {
426     static char strbuf[1024];
427     sprintf(strbuf,"%d",i);
428     string s = strbuf;
429     return s;
430     }

  ViewVC Help
Powered by ViewVC