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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 365 - (hide annotations) (download)
Thu Feb 10 19:16:31 2005 UTC (19 years, 2 months 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 schoenebeck 2 /***************************************************************************
2     * *
3     * libgig - C++ cross-platform Gigasampler format file loader library *
4     * *
5 schoenebeck 55 * Copyright (C) 2003, 2004 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 2 #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 schoenebeck 220
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 schoenebeck 2 #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 schoenebeck 220 string ToString(int i);
73    
74     #ifndef HAVE_SNDFILE
75 schoenebeck 2 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 schoenebeck 220 #endif // !HAVE_SNDFILE
89 schoenebeck 2
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 schoenebeck 220 #ifndef HAVE_SNDFILE
153 schoenebeck 2 hAFlib = NULL;
154     openAFlib();
155 schoenebeck 220 #endif // !HAVE_SNDFILE
156 schoenebeck 2 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 persson 365 // 24 bit is truncated to 16 by Sample::Read at the moment
206     pSamplePiece += readinthisrun * (2 * pSample->Channels); // readinthisrun * pSample->FrameSize;
207 schoenebeck 2 readsamples += readinthisrun;
208     } while (readinthisrun == samplepiecesize);
209    
210     if (pSample->Compressed) { // hack
211     pSample->SamplesTotal = readsamples;
212 persson 365 pSample->BitDepth = 16;
213 schoenebeck 2 }
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 schoenebeck 220 #ifndef HAVE_SNDFILE
245 schoenebeck 2 closeAFlib();
246 schoenebeck 220 #endif // !HAVE_SNDFILE
247 schoenebeck 2 }
248    
249     int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
250 schoenebeck 220 #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 schoenebeck 2 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 schoenebeck 220 #endif // HAVE_SNDFILE
303 schoenebeck 55
304 schoenebeck 220 return 0; // success
305 schoenebeck 2 }
306    
307 schoenebeck 220 #ifndef HAVE_SNDFILE
308 schoenebeck 2 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 schoenebeck 220 #endif // !HAVE_SNDFILE
330 schoenebeck 2
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