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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 55 - (show annotations) (download)
Tue Apr 27 09:06:07 2004 UTC (15 years, 3 months ago) by schoenebeck
File size: 12022 byte(s)
updated copyright header for 2004

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 <stdlib.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <dirent.h>
46 #include <errno.h>
47 #include <dlfcn.h>
48 #include <audiofile.h>
49 #include "gig.h"
50
51 using namespace std;
52
53 typedef map<unsigned int, bool> OrderMap;
54 OrderMap* pOrderedSamples = NULL;
55
56 void PrintUsage();
57 void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered);
58 int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate);
59 void* hAFlib; // handle to libaudiofile
60 void openAFlib(void);
61 void closeAFlib(void);
62 // pointers to libaudiofile functions
63 AFfilesetup(*_afNewFileSetup)(void);
64 void(*_afFreeFileSetup)(AFfilesetup);
65 void(*_afInitChannels)(AFfilesetup,int,int);
66 void(*_afInitSampleFormat)(AFfilesetup,int,int,int);
67 void(*_afInitFileFormat)(AFfilesetup,int);
68 void(*_afInitRate)(AFfilesetup,int,double);
69 int(*_afWriteFrames)(AFfilehandle,int,const void*,int);
70 AFfilehandle(*_afOpenFile)(const char*,const char*,AFfilesetup);
71 int(*_afCloseFile)(AFfilehandle file);
72 string ToString(int i);
73
74 int main(int argc, char *argv[]) {
75 if (argc < 3) {
76 PrintUsage();
77 return EXIT_FAILURE;
78 }
79 if (argc > 3) { // extracting specific samples
80 pOrderedSamples = new OrderMap;
81 for (int i = 3; i < argc; i++) {
82 unsigned int index = atoi(argv[i]);
83 (*pOrderedSamples)[index] = true;
84 }
85 }
86 FILE* hFile = fopen(argv[1], "r");
87 if (!hFile) {
88 cout << "Invalid input file argument!" << endl;
89 return EXIT_FAILURE;
90 }
91 fclose(hFile);
92 DIR* dir = opendir(argv[2]);
93 if (!dir) {
94 cout << "Unable to open DESTDIR: ";
95 switch (errno) {
96 case EACCES: cout << "Permission denied." << endl;
97 break;
98 case EMFILE: cout << "Too many file descriptors in use by process." << endl;
99 break;
100 case ENFILE: cout << "Too many files are currently open in the system." << endl;
101 break;
102 case ENOENT: cout << "Directory does not exist, or name is an empty string." << endl;
103 break;
104 case ENOMEM: cout << "Insufficient memory to complete the operation." << endl;
105 break;
106 case ENOTDIR: cout << "Is not a directory." << endl;
107 break;
108 default: cout << "Unknown error" << endl;
109 }
110 return EXIT_FAILURE;
111 }
112 if (dir) closedir(dir);
113 try {
114 RIFF::File* riff = new RIFF::File(argv[1]);
115 gig::File* gig = new gig::File(riff);
116 cout << "Extracting samples from \"" << argv[1] << "\" to directory \"" << argv[2] << "\"." << endl << flush;
117 ExtractSamples(gig, argv[2], pOrderedSamples);
118 cout << "Extraction finished." << endl << flush;
119 delete gig;
120 delete riff;
121 if (pOrderedSamples) delete pOrderedSamples;
122 }
123 catch (RIFF::Exception e) {
124 e.PrintMessage();
125 return EXIT_FAILURE;
126 }
127 catch (...) {
128 cout << "Unknown exception while trying to parse file." << endl;
129 return EXIT_FAILURE;
130 }
131
132 return EXIT_SUCCESS;
133 }
134
135 void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered) {
136 hAFlib = NULL;
137 openAFlib();
138 uint8_t* pWave = NULL;
139 long BufferSize = 0;
140 int samples = 0;
141 cout << "Seeking for available samples..." << flush;
142 gig::Sample* pSample = gig->GetFirstSample();
143 cout << "OK" << endl << flush;
144 while (pSample) {
145 samples++;
146 if (ordered) {
147 if ((*ordered)[samples] == false) {
148 pSample = gig->GetNextSample();
149 continue;
150 }
151 }
152 string name = pSample->pInfo->Name;
153 string filename = destdir;
154 if (filename[filename.size() - 1] != '/') filename += "/";
155 filename += ToString(samples);
156 filename += "_";
157 if (name == "") {
158 name = "(NO NAME)";
159 filename += "NONAME";
160 }
161 else {
162 filename += name;
163 name.insert(0, "\"");
164 name += "\"";
165 }
166 filename += ".wav";
167 if (pSample->Compressed) cout << "Decompressing ";
168 else cout << "Extracting ";
169 cout << "Sample " << samples << ") " << name << " (" << pSample->BitDepth <<"Bits, " << pSample->SamplesPerSecond << "Hz, " << pSample->Channels << " Channels, " << pSample->SamplesTotal << " Samples)..." << flush;
170
171
172 #if USE_DISK_STREAMING
173 if (pSample->Compressed) { // hack
174 pSample->BitDepth = 16;
175 pSample->FrameSize = 4;
176 }
177
178 long neededsize = (pSample->Compressed) ? 10485760 /* 10 MB buffer */
179 : pSample->SamplesTotal * pSample->FrameSize;
180 if (BufferSize < neededsize) {
181 if (pWave) delete[] pWave;
182 pWave = new uint8_t[neededsize];
183 BufferSize = neededsize;
184 }
185 # if HASHED_READS_TEST
186 unsigned long readsamples = 0,
187 readinthisrun = 0,
188 samplepiecesize = 2000;
189 uint8_t* pSamplePiece = pWave;
190 do { // we read the sample in small pieces and increment the size with each run just to test streaming capability
191 readinthisrun = pSample->Read(pSamplePiece, ++samplepiecesize);
192 pSamplePiece += readinthisrun * pSample->FrameSize;
193 readsamples += readinthisrun;
194 } while (readinthisrun == samplepiecesize);
195
196 if (pSample->Compressed) { // hack
197 pSample->SamplesTotal = readsamples;
198 }
199 # else // read in one piece
200 if (pSample->Compressed) {
201 pSample->SamplesTotal = pSample->Read(pWave, 10485760 >> 2); // assumes 16 bit stereo
202 }
203 else {
204 pSample->Read(pWave, pSample->SamplesTotal);
205 }
206 # endif // HASHED_READS_TEST
207 #else // no disk streaming
208 if (pSample->Compressed) {
209 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;
210 }
211 else pWave = (uint8_t*) pSample->LoadSampleData(); // load wave into RAM
212 #endif // USE_DISK_STREAMING
213 if (pWave) {
214 int res = writeWav(filename.c_str(),
215 pWave,
216 pSample->SamplesTotal,
217 pSample->Channels,
218 pSample->BitDepth,
219 pSample->SamplesPerSecond);
220 if (res < 0) cout << "Couldn't write sample data." << endl;
221 else cout << "ok" << endl;
222 pSample->ReleaseSampleData(); // free wave from RAM
223 }
224 else cout << "Failed to load sample data." << endl;
225
226 pSample = gig->GetNextSample();
227 }
228 if (pWave) delete[] (uint8_t*) pWave;
229 closeAFlib();
230 }
231
232 int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
233 AFfilesetup setup = _afNewFileSetup();
234 _afInitFileFormat(setup, AF_FILE_WAVE);
235 _afInitChannels(setup, AF_DEFAULT_TRACK, channels);
236 _afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, bitdepth);
237 _afInitRate(setup, AF_DEFAULT_TRACK, rate);
238 if (setup == AF_NULL_FILESETUP) return -1;
239 AFfilehandle hFile = _afOpenFile(filename, "w", setup);
240 if (hFile == AF_NULL_FILEHANDLE) return -1;
241 if (_afWriteFrames(hFile, AF_DEFAULT_TRACK, samples, samplecount) < 0) return -1;
242 _afCloseFile(hFile);
243 _afFreeFileSetup(setup);
244
245 return 0;
246 }
247
248 void openAFlib() {
249 hAFlib = dlopen("libaudiofile.so", RTLD_NOW);
250 if (!hAFlib) {
251 cout << "Unable to load library libaudiofile.so: " << dlerror() << endl;
252 return;
253 }
254 _afNewFileSetup = (AFfilesetup(*)(void)) dlsym(hAFlib, "afNewFileSetup");
255 _afFreeFileSetup = (void(*)(AFfilesetup)) dlsym(hAFlib, "afFreeFileSetup");
256 _afInitChannels = (void(*)(AFfilesetup,int,int)) dlsym(hAFlib, "afInitChannels");
257 _afInitSampleFormat = (void(*)(AFfilesetup,int,int,int)) dlsym(hAFlib, "afInitSampleFormat");
258 _afInitFileFormat = (void(*)(AFfilesetup,int)) dlsym(hAFlib, "afInitFileFormat");
259 _afInitRate = (void(*)(AFfilesetup,int,double)) dlsym(hAFlib, "afInitRate");
260 _afWriteFrames = (int(*)(AFfilehandle,int,const void*,int)) dlsym(hAFlib, "afWriteFrames");
261 _afOpenFile = (AFfilehandle(*)(const char*,const char*,AFfilesetup)) dlsym(hAFlib, "afOpenFile");
262 _afCloseFile = (int(*)(AFfilehandle file)) dlsym(hAFlib, "afCloseFile");
263 if (dlerror()) cout << "Failed to load function from libaudiofile.so: " << dlerror() << endl;
264 }
265
266 void closeAFlib() {
267 if (hAFlib) dlclose(hAFlib);
268 }
269
270 void PrintUsage() {
271 cout << "gigextract - extracts samples from a Gigasampler file." << endl;
272 cout << endl;
273 cout << "Usage: gigextract GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl;
274 cout << endl;
275 cout << " GIGFILE Input Gigasampler (.gig) file." << endl;
276 cout << endl;
277 cout << " DESTDIR Destination directory where all .wav files will be written to." << endl;
278 cout << endl;
279 cout << " SAMPLENR Index (/indices) of Sample(s) which should be extracted." << endl;
280 cout << " If no sample indices are given, all samples will be extracted" << endl;
281 cout << " (use gigdump to look for available samples)." << endl;
282 cout << endl;
283 }
284
285 string ToString(int i) {
286 static char strbuf[1024];
287 sprintf(strbuf,"%d",i);
288 string s = strbuf;
289 return s;
290 }

  ViewVC Help
Powered by ViewVC