00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028
00029
00030
00031
00032 #define USE_DISK_STREAMING 1
00033
00034
00035
00036
00037
00038 #define HASHED_READS_TEST 1
00039
00040 #include <iostream>
00041 #include <cstdlib>
00042 #include <string.h>
00043 #include <string>
00044 #include <stdlib.h>
00045 #include <sys/types.h>
00046 #include <sys/stat.h>
00047 #include <dirent.h>
00048 #include <errno.h>
00049 #include <dlfcn.h>
00050
00051
00052 #ifdef WIN32
00053 # define HAVE_SNDFILE 1
00054 #endif // WIN32
00055
00056
00057 #if !HAVE_SNDFILE && !HAVE_AUDIOFILE
00058 # error "Neither libsndfile nor libaudiofile seem to be available!"
00059 # error "(HAVE_SNDFILE and HAVE_AUDIOFILE are both false)"
00060 #endif
00061
00062
00063 #if HAVE_SNDFILE
00064 # include <sndfile.h>
00065 #else
00066 # include <audiofile.h>
00067 #endif // HAVE_SNDFILE
00068
00069 #include "gig.h"
00070
00071 using namespace std;
00072
00073 typedef map<unsigned int, bool> OrderMap;
00074 OrderMap* pOrderedSamples = NULL;
00075
00076 string Revision();
00077 void PrintVersion();
00078 void PrintUsage();
00079 void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered);
00080 int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate);
00081 string ToString(int i);
00082
00083 #if !HAVE_SNDFILE // use libaudiofile
00084 void* hAFlib;
00085 void openAFlib(void);
00086 void closeAFlib(void);
00087
00088 AFfilesetup(*_afNewFileSetup)(void);
00089 void(*_afFreeFileSetup)(AFfilesetup);
00090 void(*_afInitChannels)(AFfilesetup,int,int);
00091 void(*_afInitSampleFormat)(AFfilesetup,int,int,int);
00092 void(*_afInitFileFormat)(AFfilesetup,int);
00093 void(*_afInitRate)(AFfilesetup,int,double);
00094 int(*_afWriteFrames)(AFfilehandle,int,const void*,int);
00095 AFfilehandle(*_afOpenFile)(const char*,const char*,AFfilesetup);
00096 int(*_afCloseFile)(AFfilehandle file);
00097 #endif
00098
00099 int main(int argc, char *argv[]) {
00100 if (argc >= 2) {
00101 if (argv[1][0] == '-') {
00102 switch (argv[1][1]) {
00103 case 'v':
00104 PrintVersion();
00105 return EXIT_SUCCESS;
00106 }
00107 }
00108 }
00109 if (argc < 3) {
00110 PrintUsage();
00111 return EXIT_FAILURE;
00112 }
00113 if (argc > 3) {
00114 pOrderedSamples = new OrderMap;
00115 for (int i = 3; i < argc; i++) {
00116 unsigned int index = atoi(argv[i]);
00117 (*pOrderedSamples)[index] = true;
00118 }
00119 }
00120 FILE* hFile = fopen(argv[1], "r");
00121 if (!hFile) {
00122 cout << "Invalid input file argument!" << endl;
00123 return EXIT_FAILURE;
00124 }
00125 fclose(hFile);
00126 DIR* dir = opendir(argv[2]);
00127 if (!dir) {
00128 cout << "Unable to open DESTDIR: ";
00129 switch (errno) {
00130 case EACCES: cout << "Permission denied." << endl;
00131 break;
00132 case EMFILE: cout << "Too many file descriptors in use by process." << endl;
00133 break;
00134 case ENFILE: cout << "Too many files are currently open in the system." << endl;
00135 break;
00136 case ENOENT: cout << "Directory does not exist, or name is an empty string." << endl;
00137 break;
00138 case ENOMEM: cout << "Insufficient memory to complete the operation." << endl;
00139 break;
00140 case ENOTDIR: cout << "Is not a directory." << endl;
00141 break;
00142 default: cout << "Unknown error" << endl;
00143 }
00144 return EXIT_FAILURE;
00145 }
00146 if (dir) closedir(dir);
00147 try {
00148 RIFF::File* riff = new RIFF::File(argv[1]);
00149 gig::File* gig = new gig::File(riff);
00150 cout << "Extracting samples from \"" << argv[1] << "\" to directory \"" << argv[2] << "\"." << endl << flush;
00151 ExtractSamples(gig, argv[2], pOrderedSamples);
00152 cout << "Extraction finished." << endl << flush;
00153 delete gig;
00154 delete riff;
00155 if (pOrderedSamples) delete pOrderedSamples;
00156 }
00157 catch (RIFF::Exception e) {
00158 e.PrintMessage();
00159 return EXIT_FAILURE;
00160 }
00161 catch (...) {
00162 cout << "Unknown exception while trying to parse file." << endl;
00163 return EXIT_FAILURE;
00164 }
00165
00166 return EXIT_SUCCESS;
00167 }
00168
00169 void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered) {
00170 #if !HAVE_SNDFILE // use libaudiofile
00171 hAFlib = NULL;
00172 openAFlib();
00173 #endif // !HAVE_SNDFILE
00174 uint8_t* pWave = NULL;
00175 long BufferSize = 0;
00176 int samples = 0;
00177 cout << "Seeking for available samples..." << flush;
00178 gig::Sample* pSample = gig->GetFirstSample();
00179 cout << "OK" << endl << flush;
00180 while (pSample) {
00181 samples++;
00182 if (ordered) {
00183 if ((*ordered)[samples] == false) {
00184 pSample = gig->GetNextSample();
00185 continue;
00186 }
00187 }
00188 string name = pSample->pInfo->Name;
00189 string filename = destdir;
00190 if (filename[filename.size() - 1] != '/') filename += "/";
00191 filename += ToString(samples);
00192 filename += "_";
00193 if (name == "") {
00194 name = "(NO NAME)";
00195 filename += "NONAME";
00196 }
00197 else {
00198 filename += name;
00199 name.insert(0, "\"");
00200 name += "\"";
00201 }
00202 filename += ".wav";
00203 if (pSample->Compressed) cout << "Decompressing ";
00204 else cout << "Extracting ";
00205 cout << "Sample " << samples << ") " << name << " (" << pSample->BitDepth <<"Bits, " << pSample->SamplesPerSecond << "Hz, " << pSample->Channels << " Channels, " << pSample->SamplesTotal << " Samples)..." << flush;
00206
00207
00208 #if USE_DISK_STREAMING
00209 long neededsize = (pSample->Compressed) ? 10485760
00210 : pSample->SamplesTotal * pSample->FrameSize;
00211 if (BufferSize < neededsize) {
00212 if (pWave) delete[] pWave;
00213 pWave = new uint8_t[neededsize];
00214 BufferSize = neededsize;
00215 }
00216 # if HASHED_READS_TEST
00217 unsigned long readsamples = 0,
00218 readinthisrun = 0,
00219 samplepiecesize = 2000;
00220 uint8_t* pSamplePiece = pWave;
00221 do {
00222 readinthisrun = pSample->Read(pSamplePiece, ++samplepiecesize);
00223
00224 pSamplePiece += readinthisrun * (2 * pSample->Channels);
00225 readsamples += readinthisrun;
00226 } while (readinthisrun == samplepiecesize);
00227
00228 if (pSample->Compressed) {
00229 pSample->SamplesTotal = readsamples;
00230 pSample->BitDepth = 16;
00231 }
00232 # else // read in one piece
00233 if (pSample->Compressed) {
00234 pSample->SamplesTotal = pSample->Read(pWave, 10485760 >> 2);
00235 }
00236 else {
00237 pSample->Read(pWave, pSample->SamplesTotal);
00238 }
00239 # endif // HASHED_READS_TEST
00240 #else // no disk streaming
00241 if (pSample->Compressed) {
00242 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;
00243 }
00244 else pWave = (uint8_t*) pSample->LoadSampleData();
00245 #endif // USE_DISK_STREAMING
00246 if (pWave) {
00247 int res = writeWav(filename.c_str(),
00248 pWave,
00249 pSample->SamplesTotal,
00250 pSample->Channels,
00251 pSample->BitDepth,
00252 pSample->SamplesPerSecond);
00253 if (res < 0) cout << "Couldn't write sample data." << endl;
00254 else cout << "ok" << endl;
00255 pSample->ReleaseSampleData();
00256 }
00257 else cout << "Failed to load sample data." << endl;
00258
00259 pSample = gig->GetNextSample();
00260 }
00261 if (pWave) delete[] (uint8_t*) pWave;
00262 #if !HAVE_SNDFILE
00263 closeAFlib();
00264 #endif // !HAVE_SNDFILE
00265 }
00266
00267 int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
00268 #if HAVE_SNDFILE
00269 SNDFILE* hfile;
00270 SF_INFO sfinfo;
00271 int format = SF_FORMAT_WAV;
00272 switch (bitdepth) {
00273 case 8:
00274 format |= SF_FORMAT_PCM_S8;
00275 cout << "8 bit" << endl << flush;
00276 break;
00277 case 16:
00278 format |= SF_FORMAT_PCM_16;
00279 cout << "16 bit" << endl << flush;
00280 break;
00281 case 24:
00282 format |= SF_FORMAT_PCM_24;
00283 cout << "24 bit" << endl << flush;
00284 break;
00285 case 32:
00286 format |= SF_FORMAT_PCM_32;
00287 cout << "32 bit" << endl << flush;
00288 break;
00289 default:
00290 cerr << "Error: Bithdepth " << ToString(bitdepth) << " not supported by libsndfile, ignoring sample!\n" << flush;
00291 return -1;
00292 }
00293 memset(&sfinfo, 0, sizeof (sfinfo));
00294 sfinfo.samplerate = rate;
00295 sfinfo.frames = samplecount;
00296 sfinfo.channels = channels;
00297 sfinfo.format = format;
00298 if (!(hfile = sf_open(filename, SFM_WRITE, &sfinfo))) {
00299 cerr << "Error: Unable to open output file \'" << filename << "\'.\n" << flush;
00300 return -1;
00301 }
00302 if (sf_write_short(hfile, (short*)samples, channels * samplecount) != channels * samplecount) {
00303 cerr << sf_strerror(hfile) << endl << flush;
00304 sf_close(hfile);
00305 return -1;
00306 }
00307 sf_close(hfile);
00308 #else // use libaudiofile
00309 AFfilesetup setup = _afNewFileSetup();
00310 _afInitFileFormat(setup, AF_FILE_WAVE);
00311 _afInitChannels(setup, AF_DEFAULT_TRACK, channels);
00312 _afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, bitdepth);
00313 _afInitRate(setup, AF_DEFAULT_TRACK, rate);
00314 if (setup == AF_NULL_FILESETUP) return -1;
00315 AFfilehandle hFile = _afOpenFile(filename, "w", setup);
00316 if (hFile == AF_NULL_FILEHANDLE) return -1;
00317 if (_afWriteFrames(hFile, AF_DEFAULT_TRACK, samples, samplecount) < 0) return -1;
00318 _afCloseFile(hFile);
00319 _afFreeFileSetup(setup);
00320 #endif // HAVE_SNDFILE
00321
00322 return 0;
00323 }
00324
00325 #if !HAVE_SNDFILE // use libaudiofile
00326 void openAFlib() {
00327 hAFlib = dlopen("libaudiofile.so", RTLD_NOW);
00328 if (!hAFlib) {
00329 cout << "Unable to load library libaudiofile.so: " << dlerror() << endl;
00330 return;
00331 }
00332 _afNewFileSetup = (AFfilesetup(*)(void)) dlsym(hAFlib, "afNewFileSetup");
00333 _afFreeFileSetup = (void(*)(AFfilesetup)) dlsym(hAFlib, "afFreeFileSetup");
00334 _afInitChannels = (void(*)(AFfilesetup,int,int)) dlsym(hAFlib, "afInitChannels");
00335 _afInitSampleFormat = (void(*)(AFfilesetup,int,int,int)) dlsym(hAFlib, "afInitSampleFormat");
00336 _afInitFileFormat = (void(*)(AFfilesetup,int)) dlsym(hAFlib, "afInitFileFormat");
00337 _afInitRate = (void(*)(AFfilesetup,int,double)) dlsym(hAFlib, "afInitRate");
00338 _afWriteFrames = (int(*)(AFfilehandle,int,const void*,int)) dlsym(hAFlib, "afWriteFrames");
00339 _afOpenFile = (AFfilehandle(*)(const char*,const char*,AFfilesetup)) dlsym(hAFlib, "afOpenFile");
00340 _afCloseFile = (int(*)(AFfilehandle file)) dlsym(hAFlib, "afCloseFile");
00341 if (dlerror()) cout << "Failed to load function from libaudiofile.so: " << dlerror() << endl;
00342 }
00343
00344 void closeAFlib() {
00345 if (hAFlib) dlclose(hAFlib);
00346 }
00347 #endif // !HAVE_SNDFILE
00348
00349 string Revision() {
00350 string s = "$Revision: 1.7 $";
00351 return s.substr(11, s.size() - 13);
00352 }
00353
00354 void PrintVersion() {
00355 cout << "gigextract revision " << Revision() << endl;
00356 cout << "using " << gig::libraryName() << " " << gig::libraryVersion();
00357 #if HAVE_SNDFILE
00358 char versionBuffer[128];
00359 sf_command(NULL, SFC_GET_LIB_VERSION, versionBuffer, 128);
00360 cout << ", " << versionBuffer;
00361 #else // use libaudiofile
00362 cout << "\nbuilt against libaudiofile "
00363 << LIBAUDIOFILE_MAJOR_VERSION << "." << LIBAUDIOFILE_MINOR_VERSION;
00364 # ifdef LIBAUDIOFILE_MICRO_VERSION
00365 cout << "." << LIBAUDIOFILE_MICRO_VERSION;
00366 # endif // LIBAUDIOFILE_MICRO_VERSION
00367 #endif // HAVE_SNDFILE
00368 cout << endl;
00369 }
00370
00371 void PrintUsage() {
00372 cout << "gigextract - extracts samples from a Gigasampler file." << endl;
00373 cout << endl;
00374 cout << "Usage: gigextract [-v] GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl;
00375 cout << endl;
00376 cout << " GIGFILE Input Gigasampler (.gig) file." << endl;
00377 cout << endl;
00378 cout << " DESTDIR Destination directory where all .wav files will be written to." << endl;
00379 cout << endl;
00380 cout << " SAMPLENR Index (/indices) of Sample(s) which should be extracted." << endl;
00381 cout << " If no sample indices are given, all samples will be extracted" << endl;
00382 cout << " (use gigdump to look for available samples)." << endl;
00383 cout << endl;
00384 cout << " -v Print version and exit." << endl;
00385 cout << endl;
00386 }
00387
00388 string ToString(int i) {
00389 static char strbuf[1024];
00390 sprintf(strbuf,"%d",i);
00391 string s = strbuf;
00392 return s;
00393 }