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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 220 - (show annotations) (download)
Wed Aug 18 12:11:26 2004 UTC (19 years, 8 months ago) by schoenebeck
File size: 13867 byte(s)
* added support for libsndfile to the 'gigextract' tool

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 if (pSample->Compressed) { // hack
192 pSample->BitDepth = 16;
193 pSample->FrameSize = 4;
194 }
195
196 long neededsize = (pSample->Compressed) ? 10485760 /* 10 MB buffer */
197 : pSample->SamplesTotal * pSample->FrameSize;
198 if (BufferSize < neededsize) {
199 if (pWave) delete[] pWave;
200 pWave = new uint8_t[neededsize];
201 BufferSize = neededsize;
202 }
203 # if HASHED_READS_TEST
204 unsigned long readsamples = 0,
205 readinthisrun = 0,
206 samplepiecesize = 2000;
207 uint8_t* pSamplePiece = pWave;
208 do { // we read the sample in small pieces and increment the size with each run just to test streaming capability
209 readinthisrun = pSample->Read(pSamplePiece, ++samplepiecesize);
210 pSamplePiece += readinthisrun * pSample->FrameSize;
211 readsamples += readinthisrun;
212 } while (readinthisrun == samplepiecesize);
213
214 if (pSample->Compressed) { // hack
215 pSample->SamplesTotal = readsamples;
216 }
217 # else // read in one piece
218 if (pSample->Compressed) {
219 pSample->SamplesTotal = pSample->Read(pWave, 10485760 >> 2); // assumes 16 bit stereo
220 }
221 else {
222 pSample->Read(pWave, pSample->SamplesTotal);
223 }
224 # endif // HASHED_READS_TEST
225 #else // no disk streaming
226 if (pSample->Compressed) {
227 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;
228 }
229 else pWave = (uint8_t*) pSample->LoadSampleData(); // load wave into RAM
230 #endif // USE_DISK_STREAMING
231 if (pWave) {
232 int res = writeWav(filename.c_str(),
233 pWave,
234 pSample->SamplesTotal,
235 pSample->Channels,
236 pSample->BitDepth,
237 pSample->SamplesPerSecond);
238 if (res < 0) cout << "Couldn't write sample data." << endl;
239 else cout << "ok" << endl;
240 pSample->ReleaseSampleData(); // free wave from RAM
241 }
242 else cout << "Failed to load sample data." << endl;
243
244 pSample = gig->GetNextSample();
245 }
246 if (pWave) delete[] (uint8_t*) pWave;
247 #ifndef HAVE_SNDFILE
248 closeAFlib();
249 #endif // !HAVE_SNDFILE
250 }
251
252 int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
253 #if HAVE_SNDFILE
254 SNDFILE* hfile;
255 SF_INFO sfinfo;
256 int format = SF_FORMAT_WAV;
257 switch (bitdepth) {
258 case 8:
259 format |= SF_FORMAT_PCM_S8;
260 cout << "8 bit" << endl << flush;
261 break;
262 case 16:
263 format |= SF_FORMAT_PCM_16;
264 cout << "16 bit" << endl << flush;
265 break;
266 case 24:
267 format |= SF_FORMAT_PCM_24;
268 cout << "24 bit" << endl << flush;
269 break;
270 case 32:
271 format |= SF_FORMAT_PCM_32;
272 cout << "32 bit" << endl << flush;
273 break;
274 default:
275 cerr << "Error: Bithdepth " << ToString(bitdepth) << " not supported by libsndfile, ignoring sample!\n" << flush;
276 return -1;
277 }
278 memset(&sfinfo, 0, sizeof (sfinfo));
279 sfinfo.samplerate = rate;
280 sfinfo.frames = samplecount;
281 sfinfo.channels = channels;
282 sfinfo.format = format;
283 if (!(hfile = sf_open(filename, SFM_WRITE, &sfinfo))) {
284 cerr << "Error: Unable to open output file \'" << filename << "\'.\n" << flush;
285 return -1;
286 }
287 if (sf_write_short(hfile, (short*)samples, channels * samplecount) != channels * samplecount) {
288 cerr << sf_strerror(hfile) << endl << flush;
289 sf_close(hfile);
290 return -1;
291 }
292 sf_close(hfile);
293 #else
294 AFfilesetup setup = _afNewFileSetup();
295 _afInitFileFormat(setup, AF_FILE_WAVE);
296 _afInitChannels(setup, AF_DEFAULT_TRACK, channels);
297 _afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, bitdepth);
298 _afInitRate(setup, AF_DEFAULT_TRACK, rate);
299 if (setup == AF_NULL_FILESETUP) return -1;
300 AFfilehandle hFile = _afOpenFile(filename, "w", setup);
301 if (hFile == AF_NULL_FILEHANDLE) return -1;
302 if (_afWriteFrames(hFile, AF_DEFAULT_TRACK, samples, samplecount) < 0) return -1;
303 _afCloseFile(hFile);
304 _afFreeFileSetup(setup);
305 #endif // HAVE_SNDFILE
306
307 return 0; // success
308 }
309
310 #ifndef HAVE_SNDFILE
311 void openAFlib() {
312 hAFlib = dlopen("libaudiofile.so", RTLD_NOW);
313 if (!hAFlib) {
314 cout << "Unable to load library libaudiofile.so: " << dlerror() << endl;
315 return;
316 }
317 _afNewFileSetup = (AFfilesetup(*)(void)) dlsym(hAFlib, "afNewFileSetup");
318 _afFreeFileSetup = (void(*)(AFfilesetup)) dlsym(hAFlib, "afFreeFileSetup");
319 _afInitChannels = (void(*)(AFfilesetup,int,int)) dlsym(hAFlib, "afInitChannels");
320 _afInitSampleFormat = (void(*)(AFfilesetup,int,int,int)) dlsym(hAFlib, "afInitSampleFormat");
321 _afInitFileFormat = (void(*)(AFfilesetup,int)) dlsym(hAFlib, "afInitFileFormat");
322 _afInitRate = (void(*)(AFfilesetup,int,double)) dlsym(hAFlib, "afInitRate");
323 _afWriteFrames = (int(*)(AFfilehandle,int,const void*,int)) dlsym(hAFlib, "afWriteFrames");
324 _afOpenFile = (AFfilehandle(*)(const char*,const char*,AFfilesetup)) dlsym(hAFlib, "afOpenFile");
325 _afCloseFile = (int(*)(AFfilehandle file)) dlsym(hAFlib, "afCloseFile");
326 if (dlerror()) cout << "Failed to load function from libaudiofile.so: " << dlerror() << endl;
327 }
328
329 void closeAFlib() {
330 if (hAFlib) dlclose(hAFlib);
331 }
332 #endif // !HAVE_SNDFILE
333
334 void PrintUsage() {
335 cout << "gigextract - extracts samples from a Gigasampler file." << endl;
336 cout << endl;
337 cout << "Usage: gigextract GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl;
338 cout << endl;
339 cout << " GIGFILE Input Gigasampler (.gig) file." << endl;
340 cout << endl;
341 cout << " DESTDIR Destination directory where all .wav files will be written to." << endl;
342 cout << endl;
343 cout << " SAMPLENR Index (/indices) of Sample(s) which should be extracted." << endl;
344 cout << " If no sample indices are given, all samples will be extracted" << endl;
345 cout << " (use gigdump to look for available samples)." << endl;
346 cout << endl;
347 }
348
349 string ToString(int i) {
350 static char strbuf[1024];
351 sprintf(strbuf,"%d",i);
352 string s = strbuf;
353 return s;
354 }

  ViewVC Help
Powered by ViewVC