--- libgig/trunk/src/gigextract.cpp 2005/02/10 19:16:31 365 +++ libgig/trunk/src/gigextract.cpp 2006/11/24 12:50:05 933 @@ -1,9 +1,11 @@ /*************************************************************************** * * - * libgig - C++ cross-platform Gigasampler format file loader library * + * libgig - C++ cross-platform Gigasampler format file access library * * * - * Copyright (C) 2003, 2004 by Christian Schoenebeck * - * * + * Copyright (C) 2003-2006 by Christian Schoenebeck * + * * + * * + * This program is part of libgig. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -40,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +55,12 @@ # define HAVE_SNDFILE 1 #endif // WIN32 +// abort compilation here if neither libsndfile nor libaudiofile are available +#if !HAVE_SNDFILE && !HAVE_AUDIOFILE +# error "Neither libsndfile nor libaudiofile seem to be available!" +# error "(HAVE_SNDFILE and HAVE_AUDIOFILE are both false)" +#endif + // we prefer libsndfile before libaudiofile #if HAVE_SNDFILE # include @@ -66,12 +75,14 @@ typedef map OrderMap; OrderMap* pOrderedSamples = NULL; +string Revision(); +void PrintVersion(); void PrintUsage(); void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered); int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate); string ToString(int i); -#ifndef HAVE_SNDFILE +#if !HAVE_SNDFILE // use libaudiofile void* hAFlib; // handle to libaudiofile void openAFlib(void); void closeAFlib(void); @@ -88,6 +99,15 @@ #endif // !HAVE_SNDFILE int main(int argc, char *argv[]) { + if (argc >= 2) { + if (argv[1][0] == '-') { + switch (argv[1][1]) { + case 'v': + PrintVersion(); + return EXIT_SUCCESS; + } + } + } if (argc < 3) { PrintUsage(); return EXIT_FAILURE; @@ -149,13 +169,17 @@ } void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered) { -#ifndef HAVE_SNDFILE +#if !HAVE_SNDFILE // use libaudiofile hAFlib = NULL; openAFlib(); #endif // !HAVE_SNDFILE uint8_t* pWave = NULL; + int* pIntWave = NULL; long BufferSize = 0; int samples = 0; + gig::buffer_t decompressionBuffer; + decompressionBuffer.Size = 0; + unsigned long decompressionBufferSize = 0; cout << "Seeking for available samples..." << flush; gig::Sample* pSample = gig->GetFirstSample(); cout << "OK" << endl << flush; @@ -188,46 +212,70 @@ #if USE_DISK_STREAMING - long neededsize = (pSample->Compressed) ? 10485760 /* 10 MB buffer */ - : pSample->SamplesTotal * pSample->FrameSize; + long neededsize = pSample->BitDepth == 24 ? + pSample->SamplesTotal * pSample->Channels * sizeof(int) : + pSample->SamplesTotal * pSample->FrameSize; if (BufferSize < neededsize) { if (pWave) delete[] pWave; pWave = new uint8_t[neededsize]; BufferSize = neededsize; } + pIntWave = (int*)pWave; # if HASHED_READS_TEST - unsigned long readsamples = 0, - readinthisrun = 0, + unsigned long readinthisrun = 0, samplepiecesize = 2000; uint8_t* pSamplePiece = pWave; do { // we read the sample in small pieces and increment the size with each run just to test streaming capability readinthisrun = pSample->Read(pSamplePiece, ++samplepiecesize); - // 24 bit is truncated to 16 by Sample::Read at the moment - pSamplePiece += readinthisrun * (2 * pSample->Channels); // readinthisrun * pSample->FrameSize; - readsamples += readinthisrun; + pSamplePiece += readinthisrun * pSample->FrameSize; } while (readinthisrun == samplepiecesize); - if (pSample->Compressed) { // hack - pSample->SamplesTotal = readsamples; - pSample->BitDepth = 16; - } # else // read in one piece if (pSample->Compressed) { - pSample->SamplesTotal = pSample->Read(pWave, 10485760 >> 2); // assumes 16 bit stereo - } - else { + if (decompressionBufferSize < pSample->SamplesTotal) { + gig::Sample::DestroyDecompressionBuffer(decompressionBuffer); + decompressionBuffer = gig::Sample::CreateDecompressionBuffer(pSample->SamplesTotal); + decompressionBufferSize = pSample->SamplesTotal; + } + pSample->Read(pWave, pSample->SamplesTotal, &decompressionBuffer); + } else { pSample->Read(pWave, pSample->SamplesTotal); } # endif // HASHED_READS_TEST #else // no disk streaming if (pSample->Compressed) { - 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; + 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; + } else { + gig::buffer_t buffer = pSample->LoadSampleData(); // load wave into RAM + pWave = static_cast(buffer.pStart); + if (pSample->BitDepth == 24) { + long neededsize = pSample->SamplesTotal * pSample->Channels; + if (BufferSize < neededsize) { + if (pIntWave) delete[] pIntWave; + pIntWave = new int[neededsize]; + BufferSize = neededsize; + } + } } - else pWave = (uint8_t*) pSample->LoadSampleData(); // load wave into RAM #endif // USE_DISK_STREAMING if (pWave) { + + // Both libsndfile and libaudiofile uses int for 24 bit + // samples. libgig however returns 3 bytes per sample, so + // we have to convert the wave data before writing. + if (pSample->BitDepth == 24) { + int n = pSample->SamplesTotal * pSample->Channels; + for (int i = n - 1 ; i >= 0 ; i--) { +#if HAVE_SNDFILE + pIntWave[i] = pWave[i * 3] << 8 | pWave[i * 3 + 1] << 16 | pWave[i * 3 + 2] << 24; +#else + pIntWave[i] = pWave[i * 3] | pWave[i * 3 + 1] << 8 | pWave[i * 3 + 2] << 16; +#endif + } + } + int res = writeWav(filename.c_str(), - pWave, + pSample->BitDepth == 24 ? static_cast(pIntWave) : pWave, pSample->SamplesTotal, pSample->Channels, pSample->BitDepth, @@ -240,8 +288,13 @@ pSample = gig->GetNextSample(); } - if (pWave) delete[] (uint8_t*) pWave; -#ifndef HAVE_SNDFILE + gig::Sample::DestroyDecompressionBuffer(decompressionBuffer); +#if USE_DISK_STREAMING + if (pWave) delete[] pWave; +#else + if (pIntWave) delete[] pIntWave; +#endif +#if !HAVE_SNDFILE // use libaudiofile closeAFlib(); #endif // !HAVE_SNDFILE } @@ -254,19 +307,15 @@ switch (bitdepth) { case 8: format |= SF_FORMAT_PCM_S8; - cout << "8 bit" << endl << flush; break; case 16: format |= SF_FORMAT_PCM_16; - cout << "16 bit" << endl << flush; break; case 24: format |= SF_FORMAT_PCM_24; - cout << "24 bit" << endl << flush; break; case 32: format |= SF_FORMAT_PCM_32; - cout << "32 bit" << endl << flush; break; default: cerr << "Error: Bithdepth " << ToString(bitdepth) << " not supported by libsndfile, ignoring sample!\n" << flush; @@ -281,13 +330,16 @@ cerr << "Error: Unable to open output file \'" << filename << "\'.\n" << flush; return -1; } - if (sf_write_short(hfile, (short*)samples, channels * samplecount) != channels * samplecount) { + sf_count_t res = bitdepth == 24 ? + sf_write_int(hfile, static_cast(samples), channels * samplecount) : + sf_write_short(hfile, static_cast(samples), channels * samplecount); + if (res != channels * samplecount) { cerr << sf_strerror(hfile) << endl << flush; sf_close(hfile); return -1; } sf_close(hfile); -#else +#else // use libaudiofile AFfilesetup setup = _afNewFileSetup(); _afInitFileFormat(setup, AF_FILE_WAVE); _afInitChannels(setup, AF_DEFAULT_TRACK, channels); @@ -304,7 +356,7 @@ return 0; // success } -#ifndef HAVE_SNDFILE +#if !HAVE_SNDFILE // use libaudiofile void openAFlib() { hAFlib = dlopen("libaudiofile.so", RTLD_NOW); if (!hAFlib) { @@ -328,10 +380,32 @@ } #endif // !HAVE_SNDFILE +string Revision() { + string s = "$Revision: 1.9 $"; + return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword +} + +void PrintVersion() { + cout << "gigextract revision " << Revision() << endl; + cout << "using " << gig::libraryName() << " " << gig::libraryVersion(); + #if HAVE_SNDFILE + char versionBuffer[128]; + sf_command(NULL, SFC_GET_LIB_VERSION, versionBuffer, 128); + cout << ", " << versionBuffer; + #else // use libaudiofile + cout << "\nbuilt against libaudiofile " + << LIBAUDIOFILE_MAJOR_VERSION << "." << LIBAUDIOFILE_MINOR_VERSION; + # ifdef LIBAUDIOFILE_MICRO_VERSION + cout << "." << LIBAUDIOFILE_MICRO_VERSION; + # endif // LIBAUDIOFILE_MICRO_VERSION + #endif // HAVE_SNDFILE + cout << endl; +} + void PrintUsage() { cout << "gigextract - extracts samples from a Gigasampler file." << endl; cout << endl; - cout << "Usage: gigextract GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl; + cout << "Usage: gigextract [-v] GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl; cout << endl; cout << " GIGFILE Input Gigasampler (.gig) file." << endl; cout << endl; @@ -341,6 +415,8 @@ cout << " If no sample indices are given, all samples will be extracted" << endl; cout << " (use gigdump to look for available samples)." << endl; cout << endl; + cout << " -v Print version and exit." << endl; + cout << endl; } string ToString(int i) {