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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 549 - (hide annotations) (download)
Mon May 16 18:40:45 2005 UTC (15 years, 8 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 schoenebeck 2 /***************************************************************************
2     * *
3     * libgig - C++ cross-platform Gigasampler format file loader library *
4     * *
5 schoenebeck 518 * Copyright (C) 2003-2005 by Christian Schoenebeck *
6     * <cuse@users.sourceforge.net> *
7 schoenebeck 2 * *
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 schoenebeck 220 #include <string.h>
43 schoenebeck 518 #include <string>
44 schoenebeck 2 #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 schoenebeck 220
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 schoenebeck 2 #include "gig.h"
64    
65     using namespace std;
66    
67     typedef map<unsigned int, bool> OrderMap;
68     OrderMap* pOrderedSamples = NULL;
69    
70 schoenebeck 518 string Revision();
71     void PrintVersion();
72 schoenebeck 2 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 schoenebeck 220 string ToString(int i);
76    
77     #ifndef HAVE_SNDFILE
78 schoenebeck 2 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 schoenebeck 220 #endif // !HAVE_SNDFILE
92 schoenebeck 2
93     int main(int argc, char *argv[]) {
94 schoenebeck 518 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 schoenebeck 2 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 schoenebeck 220 #ifndef HAVE_SNDFILE
165 schoenebeck 2 hAFlib = NULL;
166     openAFlib();
167 schoenebeck 220 #endif // !HAVE_SNDFILE
168 schoenebeck 2 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 persson 365 // 24 bit is truncated to 16 by Sample::Read at the moment
218     pSamplePiece += readinthisrun * (2 * pSample->Channels); // readinthisrun * pSample->FrameSize;
219 schoenebeck 2 readsamples += readinthisrun;
220     } while (readinthisrun == samplepiecesize);
221    
222     if (pSample->Compressed) { // hack
223     pSample->SamplesTotal = readsamples;
224 persson 365 pSample->BitDepth = 16;
225 schoenebeck 2 }
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 schoenebeck 220 #ifndef HAVE_SNDFILE
257 schoenebeck 2 closeAFlib();
258 schoenebeck 220 #endif // !HAVE_SNDFILE
259 schoenebeck 2 }
260    
261     int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
262 schoenebeck 220 #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 schoenebeck 2 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 schoenebeck 220 #endif // HAVE_SNDFILE
315 schoenebeck 55
316 schoenebeck 220 return 0; // success
317 schoenebeck 2 }
318    
319 schoenebeck 220 #ifndef HAVE_SNDFILE
320 schoenebeck 2 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 schoenebeck 220 #endif // !HAVE_SNDFILE
342 schoenebeck 2
343 schoenebeck 518 string Revision() {
344 schoenebeck 549 string s = "$Revision: 1.6 $";
345 schoenebeck 518 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 schoenebeck 549 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 schoenebeck 518 }
366    
367 schoenebeck 2 void PrintUsage() {
368     cout << "gigextract - extracts samples from a Gigasampler file." << endl;
369     cout << endl;
370 schoenebeck 518 cout << "Usage: gigextract [-v] GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl;
371 schoenebeck 2 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 schoenebeck 518 cout << " -v Print version and exit." << endl;
381     cout << endl;
382 schoenebeck 2 }
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