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