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

Diff of /libgig/trunk/src/tools/gigextract.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

libgig/trunk/src/gigextract.cpp revision 220 by schoenebeck, Wed Aug 18 12:11:26 2004 UTC libgig/trunk/src/tools/gigextract.cpp revision 2984 by schoenebeck, Tue Sep 20 15:13:58 2016 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   libgig - C++ cross-platform Gigasampler format file loader library    *   *   libgig - C++ cross-platform Gigasampler format file access library    *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Christian Schoenebeck                     *   *   Copyright (C) 2003-2013 by Christian Schoenebeck                      *
6   *                               <cuse@users.sourceforge.net>              *   *                              <cuse@users.sourceforge.net>               *
7     *                                                                         *
8     *   This program is part of libgig.                                       *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 40  Line 42 
42  #include <iostream>  #include <iostream>
43  #include <cstdlib>  #include <cstdlib>
44  #include <string.h>  #include <string.h>
45    #include <string>
46  #include <stdlib.h>  #include <stdlib.h>
47  #include <sys/types.h>  #include <sys/types.h>
48  #include <sys/stat.h>  #include <sys/stat.h>
 #include <dirent.h>  
49  #include <errno.h>  #include <errno.h>
50  #include <dlfcn.h>  
51    #include "../gig.h"
52    
53    #ifdef _MSC_VER
54    #define S_ISDIR(x) (S_IFDIR & (x))
55    #define S_IWUSR S_IWRITE
56    #define S_IXUSR S_IEXEC
57    #endif
58    
59    #if POSIX
60    # include <dlfcn.h>
61    #endif
62    
63  // only libsndfile is available for Windows, so we use that for writing the sound files  // only libsndfile is available for Windows, so we use that for writing the sound files
64  #ifdef WIN32  #ifdef WIN32
65  # define HAVE_SNDFILE 1  # define HAVE_SNDFILE 1
66  #endif // WIN32  #endif // WIN32
67    
68    // abort compilation here if neither libsndfile nor libaudiofile are available
69    #if !HAVE_SNDFILE && !HAVE_AUDIOFILE
70    # error "Neither libsndfile nor libaudiofile seem to be available!"
71    # error "(HAVE_SNDFILE and HAVE_AUDIOFILE are both false)"
72    #endif
73    
74  // we prefer libsndfile before libaudiofile  // we prefer libsndfile before libaudiofile
75  #if HAVE_SNDFILE  #if HAVE_SNDFILE
76  # include <sndfile.h>  # include <sndfile.h>
# Line 59  Line 78 
78  # include <audiofile.h>  # include <audiofile.h>
79  #endif // HAVE_SNDFILE  #endif // HAVE_SNDFILE
80    
 #include "gig.h"  
   
81  using namespace std;  using namespace std;
82    
83  typedef map<unsigned int, bool> OrderMap;  typedef map<unsigned int, bool> OrderMap;
84  OrderMap* pOrderedSamples = NULL;  OrderMap* pOrderedSamples = NULL;
85    
86    string Revision();
87    void PrintVersion();
88  void PrintUsage();  void PrintUsage();
89  void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered);  void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered);
90  int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate);  int writeWav(gig::Sample* sample, const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate);
91  string ToString(int i);  string ToString(int i);
92    
93  #ifndef HAVE_SNDFILE  #if !HAVE_SNDFILE // use libaudiofile
94  void* hAFlib; // handle to libaudiofile  void* hAFlib; // handle to libaudiofile
95  void openAFlib(void);  void openAFlib(void);
96  void closeAFlib(void);  void closeAFlib(void);
# Line 88  int(*_afCloseFile)(AFfilehandle file); Line 107  int(*_afCloseFile)(AFfilehandle file);
107  #endif // !HAVE_SNDFILE  #endif // !HAVE_SNDFILE
108    
109  int main(int argc, char *argv[]) {  int main(int argc, char *argv[]) {
110         if (argc >= 2) {
111            if (argv[1][0] == '-') {
112                switch (argv[1][1]) {
113                    case 'v':
114                        PrintVersion();
115                        return EXIT_SUCCESS;
116                }
117            }
118        }
119      if (argc < 3) {      if (argc < 3) {
120          PrintUsage();          PrintUsage();
121          return EXIT_FAILURE;          return EXIT_FAILURE;
# Line 105  int main(int argc, char *argv[]) { Line 133  int main(int argc, char *argv[]) {
133          return EXIT_FAILURE;          return EXIT_FAILURE;
134      }      }
135      fclose(hFile);      fclose(hFile);
136      DIR* dir = opendir(argv[2]);      struct stat buf;
137      if (!dir) {      if (stat(argv[2], &buf) == -1) {
138          cout << "Unable to open DESTDIR: ";          cout << "Unable to open DESTDIR: ";
139          switch (errno) {          switch (errno) {
140              case EACCES:  cout << "Permission denied." << endl;              case EACCES:  cout << "Permission denied." << endl;
141                            break;                            break;
             case EMFILE:  cout << "Too many file descriptors in use by process." << endl;  
                           break;  
             case ENFILE:  cout << "Too many files are currently open in the system." << endl;  
                           break;  
142              case ENOENT:  cout << "Directory does not exist, or name is an empty string." << endl;              case ENOENT:  cout << "Directory does not exist, or name is an empty string." << endl;
143                            break;                            break;
144              case ENOMEM:  cout << "Insufficient memory to complete the operation." << endl;              case ENOMEM:  cout << "Insufficient memory to complete the operation." << endl;
# Line 124  int main(int argc, char *argv[]) { Line 148  int main(int argc, char *argv[]) {
148              default:      cout << "Unknown error" << endl;              default:      cout << "Unknown error" << endl;
149          }          }
150          return EXIT_FAILURE;          return EXIT_FAILURE;
151        } else if (!S_ISDIR(buf.st_mode)) {
152            cout << "Unable to open DESTDIR: Is not a directory." << endl;
153            return EXIT_FAILURE;
154        } else if (!(S_IWUSR & buf.st_mode) || !(S_IXUSR & buf.st_mode)) {
155            cout << "Unable to open DESTDIR: Permission denied." << endl;
156            return EXIT_FAILURE;
157      }      }
     if (dir) closedir(dir);  
158      try {      try {
159          RIFF::File* riff = new RIFF::File(argv[1]);          RIFF::File* riff = new RIFF::File(argv[1]);
160          gig::File*  gig  = new gig::File(riff);          gig::File*  gig  = new gig::File(riff);
# Line 148  int main(int argc, char *argv[]) { Line 177  int main(int argc, char *argv[]) {
177      return EXIT_SUCCESS;      return EXIT_SUCCESS;
178  }  }
179    
180    static std::string getLoopTypeText(gig::loop_type_t type) {
181        switch (type) {
182            case gig::loop_type_normal:
183                return "normal";
184            case gig::loop_type_bidirectional:
185                return "pingpong";
186            case gig::loop_type_backward:
187                return "backward";
188            default:
189                return "INVALID";
190        }
191    }
192    
193    static string replacePathSeparators(string s) {
194        for (int i = 0; i < s.size(); ++i)
195            if (s[i] == '/' || s[i] == '\\')
196                s[i] = '-';
197        return s;
198    }
199    
200  void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered) {  void ExtractSamples(gig::File* gig, char* destdir, OrderMap* ordered) {
201  #ifndef HAVE_SNDFILE  #if !HAVE_SNDFILE // use libaudiofile
202      hAFlib = NULL;      hAFlib = NULL;
203      openAFlib();      openAFlib();
204  #endif // !HAVE_SNDFILE  #endif // !HAVE_SNDFILE
205      uint8_t* pWave  = NULL;      uint8_t* pWave  = NULL;
206        int* pIntWave = NULL;
207      long BufferSize = 0;      long BufferSize = 0;
208      int samples     = 0;      int samples     = 0;
209        gig::buffer_t decompressionBuffer;
210        decompressionBuffer.Size = 0;
211      cout << "Seeking for available samples..." << flush;      cout << "Seeking for available samples..." << flush;
212      gig::Sample* pSample = gig->GetFirstSample();      gig::Sample* pSample = gig->GetFirstSample();
213      cout << "OK" << endl << flush;      cout << "OK" << endl << flush;
# Line 167  void ExtractSamples(gig::File* gig, char Line 219  void ExtractSamples(gig::File* gig, char
219                  continue;                  continue;
220              }              }
221          }          }
222          string name = pSample->pInfo->Name;          string name = replacePathSeparators(pSample->pInfo->Name);
223          string filename = destdir;          string filename = destdir;
224          if (filename[filename.size() - 1] != '/') filename += "/";          if (filename[filename.size() - 1] != '/') filename += "/";
225          filename += ToString(samples);          filename += ToString(samples);
# Line 184  void ExtractSamples(gig::File* gig, char Line 236  void ExtractSamples(gig::File* gig, char
236          filename += ".wav";          filename += ".wav";
237          if (pSample->Compressed) cout << "Decompressing ";          if (pSample->Compressed) cout << "Decompressing ";
238          else                     cout << "Extracting ";          else                     cout << "Extracting ";
239          cout << "Sample " << samples << ") " << name << " (" << pSample->BitDepth <<"Bits, " << pSample->SamplesPerSecond << "Hz, " << pSample->Channels << " Channels, " << pSample->SamplesTotal << " Samples)..." << flush;          cout << "Sample " << samples << ") " << name << " (" << pSample->BitDepth <<"Bits, " << pSample->SamplesPerSecond << "Hz, " << pSample->Channels << " Channels, " << pSample->SamplesTotal << " Samples";
240            if (pSample->Loops > 0) {
241                cout << ", LoopType "  << getLoopTypeText(pSample->LoopType)
242                     << ", LoopStart " << pSample->LoopStart
243                     << ", LoopEnd "   << pSample->LoopEnd;
244            }
245            cout << ")..." << flush;
246    
247    
248  #if USE_DISK_STREAMING  #if USE_DISK_STREAMING
249          if (pSample->Compressed) { // hack          long neededsize = pSample->BitDepth == 24 ?
250              pSample->BitDepth  = 16;              pSample->SamplesTotal * pSample->Channels * sizeof(int) :
251              pSample->FrameSize = 4;              pSample->SamplesTotal * pSample->FrameSize;
         }  
   
         long neededsize = (pSample->Compressed) ? 10485760 /* 10 MB buffer */  
                                                 : pSample->SamplesTotal * pSample->FrameSize;  
252          if (BufferSize < neededsize) {          if (BufferSize < neededsize) {
253              if (pWave) delete[] pWave;              if (pWave) delete[] pWave;
254              pWave = new uint8_t[neededsize];              pWave = new uint8_t[neededsize];
255              BufferSize = neededsize;              BufferSize = neededsize;
256          }          }
257            pIntWave = (int*)pWave;
258  #  if HASHED_READS_TEST  #  if HASHED_READS_TEST
259          unsigned long readsamples     = 0,          unsigned long readinthisrun   = 0,
                       readinthisrun   = 0,  
260                        samplepiecesize = 2000;                        samplepiecesize = 2000;
261          uint8_t* pSamplePiece = pWave;          uint8_t* pSamplePiece = pWave;
262          do { // we read the sample in small pieces and increment the size with each run just to test streaming capability          do { // we read the sample in small pieces and increment the size with each run just to test streaming capability
263              readinthisrun = pSample->Read(pSamplePiece, ++samplepiecesize);              readinthisrun = pSample->Read(pSamplePiece, ++samplepiecesize);
264              pSamplePiece += readinthisrun * pSample->FrameSize;              pSamplePiece += readinthisrun * pSample->FrameSize;
             readsamples  += readinthisrun;  
265          } while (readinthisrun == samplepiecesize);          } while (readinthisrun == samplepiecesize);
266    
         if (pSample->Compressed) { // hack  
             pSample->SamplesTotal = readsamples;  
         }  
267  #  else // read in one piece  #  else // read in one piece
268          if (pSample->Compressed) {          if (pSample->Compressed) {
269              pSample->SamplesTotal = pSample->Read(pWave, 10485760 >> 2); // assumes 16 bit stereo              if (decompressionBufferSize < pSample->SamplesTotal) {
270          }                  gig::Sample::DestroyDecompressionBuffer(decompressionBuffer);
271          else {                  decompressionBuffer = gig::Sample::CreateDecompressionBuffer(pSample->SamplesTotal);
272                    decompressionBufferSize = pSample->SamplesTotal;
273                }
274                pSample->Read(pWave, pSample->SamplesTotal, &decompressionBuffer);
275            } else {
276              pSample->Read(pWave, pSample->SamplesTotal);              pSample->Read(pWave, pSample->SamplesTotal);
277          }          }
278  #  endif // HASHED_READS_TEST  #  endif // HASHED_READS_TEST
279  #else // no disk streaming  #else // no disk streaming
280          if (pSample->Compressed) {          if (pSample->Compressed) {
281              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;
282            } else {
283                gig::buffer_t buffer = pSample->LoadSampleData(); // load wave into RAM
284                pWave = static_cast<uint8_t*>(buffer.pStart);
285                if (pSample->BitDepth == 24) {
286                    long neededsize = pSample->SamplesTotal * pSample->Channels;
287                    if (BufferSize < neededsize) {
288                        if (pIntWave) delete[] pIntWave;
289                        pIntWave = new int[neededsize];
290                        BufferSize = neededsize;
291                    }
292                }
293          }          }
         else pWave = (uint8_t*) pSample->LoadSampleData(); // load wave into RAM  
294  #endif // USE_DISK_STREAMING  #endif // USE_DISK_STREAMING
295          if (pWave) {          if (pWave) {
296              int res = writeWav(filename.c_str(),  
297                                 pWave,              // Both libsndfile and libaudiofile uses int for 24 bit
298                // samples. libgig however returns 3 bytes per sample, so
299                // we have to convert the wave data before writing.
300                if (pSample->BitDepth == 24) {
301                    int n = pSample->SamplesTotal * pSample->Channels;
302                    for (int i = n - 1 ; i >= 0 ; i--) {
303    #if HAVE_SNDFILE
304                        pIntWave[i] = pWave[i * 3] << 8 | pWave[i * 3 + 1] << 16 | pWave[i * 3 + 2] << 24;
305    #else
306                        pIntWave[i] = pWave[i * 3] | pWave[i * 3 + 1] << 8 | pWave[i * 3 + 2] << 16;
307    #endif
308                    }
309                }
310    
311                int res = writeWav(pSample,
312                                   filename.c_str(),
313                                   pSample->BitDepth == 24 ? static_cast<void*>(pIntWave) : pWave,
314                                 pSample->SamplesTotal,                                 pSample->SamplesTotal,
315                                 pSample->Channels,                                 pSample->Channels,
316                                 pSample->BitDepth,                                 pSample->BitDepth,
# Line 243  void ExtractSamples(gig::File* gig, char Line 323  void ExtractSamples(gig::File* gig, char
323    
324          pSample = gig->GetNextSample();          pSample = gig->GetNextSample();
325      }      }
326      if (pWave) delete[] (uint8_t*) pWave;      gig::Sample::DestroyDecompressionBuffer(decompressionBuffer);
327  #ifndef HAVE_SNDFILE  #if USE_DISK_STREAMING
328        if (pWave) delete[] pWave;
329    #else
330        if (pIntWave) delete[] pIntWave;
331    #endif
332    #if !HAVE_SNDFILE // use libaudiofile
333      closeAFlib();      closeAFlib();
334  #endif // !HAVE_SNDFILE  #endif // !HAVE_SNDFILE
335  }  }
336    
337  int writeWav(const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {  int writeWav(gig::Sample* sample, const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
338  #if HAVE_SNDFILE  #if HAVE_SNDFILE
339      SNDFILE* hfile;      SNDFILE* hfile;
340      SF_INFO  sfinfo;      SF_INFO  sfinfo;
341        SF_INSTRUMENT instr;
342      int format = SF_FORMAT_WAV;      int format = SF_FORMAT_WAV;
343      switch (bitdepth) {      switch (bitdepth) {
344          case 8:          case 8:
345              format |= SF_FORMAT_PCM_S8;              format |= SF_FORMAT_PCM_S8;
             cout << "8 bit" << endl << flush;  
346              break;              break;
347          case 16:          case 16:
348              format |= SF_FORMAT_PCM_16;              format |= SF_FORMAT_PCM_16;
             cout << "16 bit" << endl << flush;  
349              break;              break;
350          case 24:          case 24:
351              format |= SF_FORMAT_PCM_24;              format |= SF_FORMAT_PCM_24;
             cout << "24 bit" << endl << flush;  
352              break;              break;
353          case 32:          case 32:
354              format |= SF_FORMAT_PCM_32;              format |= SF_FORMAT_PCM_32;
             cout << "32 bit" << endl << flush;  
355              break;              break;
356          default:          default:
357              cerr << "Error: Bithdepth " << ToString(bitdepth) << " not supported by libsndfile, ignoring sample!\n" << flush;              cerr << "Error: Bithdepth " << ToString(bitdepth) << " not supported by libsndfile, ignoring sample!\n" << flush;
358              return -1;              return -1;
359      }      }
360      memset(&sfinfo, 0, sizeof (sfinfo));      memset(&sfinfo, 0, sizeof (sfinfo));
361        memset(&instr, 0, sizeof (instr));
362      sfinfo.samplerate = rate;      sfinfo.samplerate = rate;
363      sfinfo.frames     = samplecount;      sfinfo.frames     = samplecount;
364      sfinfo.channels   = channels;      sfinfo.channels   = channels;
# Line 284  int writeWav(const char* filename, void* Line 367  int writeWav(const char* filename, void*
367          cerr << "Error: Unable to open output file \'" << filename << "\'.\n" << flush;          cerr << "Error: Unable to open output file \'" << filename << "\'.\n" << flush;
368          return -1;          return -1;
369      }      }
370      if (sf_write_short(hfile, (short*)samples, channels * samplecount) != channels * samplecount) {      instr.basenote = sample->MIDIUnityNote;
371        instr.detune = sample->FineTune;
372        if (sample->Loops > 0) {
373            instr.loop_count = 1;
374            switch (sample->LoopType) {
375                case gig::loop_type_normal:
376                    instr.loops[0].mode = SF_LOOP_FORWARD;
377                    break;
378                case gig::loop_type_bidirectional:
379                    instr.loops[0].mode = SF_LOOP_ALTERNATING;
380                    break;
381                case gig::loop_type_backward:
382                    instr.loops[0].mode = SF_LOOP_BACKWARD;
383                    break;
384                default:
385                    instr.loops[0].mode = SF_LOOP_NONE;
386                    break;
387            }
388            instr.loops[0].start = sample->LoopStart;
389            instr.loops[0].end   = sample->LoopEnd;
390            instr.loops[0].count = sample->LoopPlayCount;
391        }
392        sf_command(hfile, SFC_SET_INSTRUMENT, &instr, sizeof(instr));
393        sf_count_t res = bitdepth == 24 ?
394            sf_write_int(hfile, static_cast<int*>(samples), channels * samplecount) :
395            sf_write_short(hfile, static_cast<short*>(samples), channels * samplecount);
396        if (res != channels * samplecount) {
397          cerr << sf_strerror(hfile) << endl << flush;          cerr << sf_strerror(hfile) << endl << flush;
398          sf_close(hfile);          sf_close(hfile);
399          return -1;          return -1;
400      }      }
401      sf_close(hfile);      sf_close(hfile);
402  #else  #else // use libaudiofile
403      AFfilesetup setup = _afNewFileSetup();      AFfilesetup setup = _afNewFileSetup();
404      _afInitFileFormat(setup, AF_FILE_WAVE);      _afInitFileFormat(setup, AF_FILE_WAVE);
405      _afInitChannels(setup, AF_DEFAULT_TRACK, channels);      _afInitChannels(setup, AF_DEFAULT_TRACK, channels);
# Line 307  int writeWav(const char* filename, void* Line 416  int writeWav(const char* filename, void*
416      return 0; // success      return 0; // success
417  }  }
418    
419  #ifndef HAVE_SNDFILE  #if !HAVE_SNDFILE // use libaudiofile
420  void openAFlib() {  void openAFlib() {
421      hAFlib = dlopen("libaudiofile.so", RTLD_NOW);      hAFlib = dlopen("libaudiofile.so", RTLD_NOW);
422      if (!hAFlib) {      if (!hAFlib) {
# Line 331  void closeAFlib() { Line 440  void closeAFlib() {
440  }  }
441  #endif // !HAVE_SNDFILE  #endif // !HAVE_SNDFILE
442    
443    string Revision() {
444        string s = "$Revision$";
445        return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
446    }
447    
448    void PrintVersion() {
449        cout << "gigextract revision " << Revision() << endl;
450        cout << "using " << gig::libraryName() << " " << gig::libraryVersion();
451        #if HAVE_SNDFILE
452        char versionBuffer[128];
453        sf_command(NULL, SFC_GET_LIB_VERSION, versionBuffer, 128);
454        cout << ", " << versionBuffer;
455        #else // use libaudiofile
456        cout << "\nbuilt against libaudiofile "
457             << LIBAUDIOFILE_MAJOR_VERSION << "." << LIBAUDIOFILE_MINOR_VERSION;
458        # ifdef LIBAUDIOFILE_MICRO_VERSION
459        cout << "." << LIBAUDIOFILE_MICRO_VERSION;
460        # endif // LIBAUDIOFILE_MICRO_VERSION
461        #endif // HAVE_SNDFILE
462        cout << endl;
463    }
464    
465  void PrintUsage() {  void PrintUsage() {
466      cout << "gigextract - extracts samples from a Gigasampler file." << endl;      cout << "gigextract - extracts samples from a Gigasampler file." << endl;
467      cout << endl;      cout << endl;
468      cout << "Usage: gigextract GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl;      cout << "Usage: gigextract [-v] GIGFILE DESTDIR [SAMPLENR] [ [SAMPLENR] ...]" << endl;
469      cout << endl;      cout << endl;
470      cout << "   GIGFILE  Input Gigasampler (.gig) file." << endl;      cout << "   GIGFILE  Input Gigasampler (.gig) file." << endl;
471      cout << endl;      cout << endl;
# Line 344  void PrintUsage() { Line 475  void PrintUsage() {
475      cout << "            If no sample indices are given, all samples will be extracted" << endl;      cout << "            If no sample indices are given, all samples will be extracted" << endl;
476      cout << "            (use gigdump to look for available samples)." << endl;      cout << "            (use gigdump to look for available samples)." << endl;
477      cout << endl;      cout << endl;
478        cout << "   -v       Print version and exit." << endl;
479        cout << endl;
480  }  }
481    
482  string ToString(int i) {  string ToString(int i) {

Legend:
Removed from v.220  
changed lines
  Added in v.2984

  ViewVC Help
Powered by ViewVC