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

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

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

libgig/trunk/src/korg2gig.cpp revision 2543 by schoenebeck, Sat May 10 02:06:58 2014 UTC libgig/trunk/src/tools/korg2gig.cpp revision 3175 by schoenebeck, Thu May 11 11:34:19 2017 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2014 Christian Schoenebeck                              *   *   Copyright (C) 2014-2017 Christian Schoenebeck                         *
4   *                      <cuse@users.sourceforge.net>                       *   *                      <cuse@users.sourceforge.net>                       *
5   *                                                                         *   *                                                                         *
6   *   This program is part of libgig.                                       *   *   This program is part of libgig.                                       *
# Line 34  Line 34 
34  # include <unistd.h>  # include <unistd.h>
35  #endif  #endif
36    
37  #include "Korg.h"  #include "../Korg.h"
38  #include "gig.h"  #include "../gig.h"
39    
40  using namespace std;  using namespace std;
41    
# Line 63  static void printUsage() { Line 63  static void printUsage() {
63      cout << endl;      cout << endl;
64  }  }
65    
66    static bool beginsWith(const string& haystack, const string& needle) {
67        return haystack.substr(0, needle.size()) == needle;
68    }
69    
70  static bool endsWith(const string& haystack, const string& needle) {  static bool endsWith(const string& haystack, const string& needle) {
71        if (haystack.size() < needle.size()) return false;
72      return haystack.substr(haystack.size() - needle.size(), needle.size()) == needle;      return haystack.substr(haystack.size() - needle.size(), needle.size()) == needle;
73  }  }
74    
# Line 210  inline string parseNumberRange(const str Line 215  inline string parseNumberRange(const str
215      stripWhiteSpace(w);      stripWhiteSpace(w);
216      stripLeftOrRightMarkerAtEnd(w);      stripLeftOrRightMarkerAtEnd(w);
217      string result = parseNumberRangeAtEnd(w, from, to);      string result = parseNumberRangeAtEnd(w, from, to);
218      if (result == w) return s; // parse error occured, return original input s      if (result == w) return s; // parse error occurred, return original input s
219      stripWhiteSpace(result);      stripWhiteSpace(result);
220      return result;      return result;
221  }  }
# Line 306  static set<DLS::range_t> collectVelocity Line 311  static set<DLS::range_t> collectVelocity
311      set<DLS::range_t> velocityRanges;      set<DLS::range_t> velocityRanges;
312      for (int i = 0; i < group.size(); ++i) {      for (int i = 0; i < group.size(); ++i) {
313          Korg::KMPInstrument* instr = group[i];          Korg::KMPInstrument* instr = group[i];
314          int iLowerKey = 0;          uint16_t iLowerKey = 0;
315          for (int k = 0; k < instr->GetRegionCount(); ++k) {          for (int k = 0; k < instr->GetRegionCount(); ++k) {
316              Korg::KMPRegion* rgn = instr->GetRegion(k);              Korg::KMPRegion* rgn = instr->GetRegion(k);
317              DLS::range_t keyRange2 = { iLowerKey, rgn->TopKey };              DLS::range_t keyRange2 = { iLowerKey, rgn->TopKey };
# Line 315  static set<DLS::range_t> collectVelocity Line 320  static set<DLS::range_t> collectVelocity
320                  int from, to;                  int from, to;
321                  string baseName = parseNumberRange(instr->Name(), from, to);                  string baseName = parseNumberRange(instr->Name(), from, to);
322                  if (baseName != instr->Name()) { // number range like "003-120" found in instrument name ...                  if (baseName != instr->Name()) { // number range like "003-120" found in instrument name ...
323                      DLS::range_t velRange = { from, to };                      DLS::range_t velRange = { uint16_t(from), uint16_t(to) };
324                      velocityRanges.insert(velRange);                      velocityRanges.insert(velRange);
325                  }                  }
326              }              }
# Line 324  static set<DLS::range_t> collectVelocity Line 329  static set<DLS::range_t> collectVelocity
329      return velocityRanges;      return velocityRanges;
330  }  }
331    
332    /**
333     * Ensure that the given list of ranges covers the full range between 0 .. 127.
334     *
335     * @param orig - (input) original set of ranges (read only)
336     * @param corrected - (output) corrected set of ranges (will be cleared and refilled)
337     * @return map that pairs respective original range with respective corrected range
338     */
339    static map<DLS::range_t,DLS::range_t> killGapsInRanges(const set<DLS::range_t>& orig, set<DLS::range_t>& corrected) {
340        map<DLS::range_t,DLS::range_t> result;
341        corrected.clear();
342        if (orig.empty()) return result;
343    
344        int iLow = 0;
345        int i = 0;
346        for (set<DLS::range_t>::const_iterator it = orig.begin(); it != orig.end(); ++it, ++i) {
347            DLS::range_t r = *it;
348            r.low = iLow;
349            iLow = r.high + 1;
350            if (i == orig.size() - 1) r.high = 127;
351            corrected.insert(r);
352            result[*it] = r;
353        }
354        return result;
355    }
356    
357    static void printRanges(const set<DLS::range_t>& ranges) {
358        cout << "{ ";
359        for (set<DLS::range_t>::const_iterator it = ranges.begin(); it != ranges.end(); ++it) {
360            if (it != ranges.begin()) cout << ", ";
361            cout << (int)it->low << ".." << (int)it->high;
362        }
363        cout << " }" << flush;
364    }
365    
366  static vector<Korg::KSFSample*>     ksfSamples;      // input .KSF files  static vector<Korg::KSFSample*>     ksfSamples;      // input .KSF files
367  static vector<Korg::KMPInstrument*> kmpInstruments;  // input .KMP files  static vector<Korg::KMPInstrument*> kmpInstruments;  // input .KMP files
368  static gig::File* g_gig = NULL;                      // output .gig file  static gig::File* g_gig = NULL;                      // output .gig file
# Line 412  static gig::Sample* findOrCreateGigSampl Line 451  static gig::Sample* findOrCreateGigSampl
451          gigSampleGroup->Name = baseName;          gigSampleGroup->Name = baseName;
452      }      }
453    
454        if (kmpRegion->SampleFileName == "SKIPPEDSAMPL" ||
455            (beginsWith(kmpRegion->SampleFileName, "INTERNAL") && !endsWith(kmpRegion->SampleFileName, ".KSF")))
456        {
457            return NULL;
458        }
459    
460      Korg::KSFSample* ksfSample = findKSFSampleWithFileName(kmpRegion->FullSampleFileName());      Korg::KSFSample* ksfSample = findKSFSampleWithFileName(kmpRegion->FullSampleFileName());
461      if (!ksfSample)      if (!ksfSample)
462          throw Korg::Exception("Internal error: Could not resolve KSFSample object");          throw Korg::Exception("Internal error: Could not resolve KSFSample object");
# Line 432  static void loadKorgFile(const string& f Line 477  static void loadKorgFile(const string& f
477    
478              for (int i = 0; i < instr->GetRegionCount(); ++i) {              for (int i = 0; i < instr->GetRegionCount(); ++i) {
479                  Korg::KMPRegion* rgn = instr->GetRegion(i);                  Korg::KMPRegion* rgn = instr->GetRegion(i);
480                    if (rgn->SampleFileName == "SKIPPEDSAMPL") {
481                        cout << "WARNING: 'SKIPPEDSAMPL' as sample reference found!\n";
482                        continue;
483                    } else if (beginsWith(rgn->SampleFileName, "INTERNAL") &&
484                               !endsWith(rgn->SampleFileName, ".KSF")) {
485                        cout << "WARNING: One of the KORG instrument's internal samples was referenced as sample!\n";
486                        continue;
487                    }
488                  // check if the sample referenced by this region was already                  // check if the sample referenced by this region was already
489                  // loaded, if not then load it ...                  // loaded, if not then load it ...
490                  if (!findKSFSampleWithFileName(rgn->FullSampleFileName()))                  if (!findKSFSampleWithFileName(rgn->FullSampleFileName()))
# Line 456  static void loadKorgFile(const string& f Line 509  static void loadKorgFile(const string& f
509          exit(EXIT_FAILURE);          exit(EXIT_FAILURE);
510      } catch (...) {      } catch (...) {
511          cerr << "Failed opening input file '" << filename << "':" << endl;          cerr << "Failed opening input file '" << filename << "':" << endl;
512          cerr << "Unknown exception occured while trying to access input file." << endl;          cerr << "Unknown exception occurred while trying to access input file." << endl;
513          exit(EXIT_FAILURE);          exit(EXIT_FAILURE);
514      }      }
515  }  }
# Line 484  int main(int argc, char *argv[]) { Line 537  int main(int argc, char *argv[]) {
537      bool bForce = false;      bool bForce = false;
538    
539      // validate & parse arguments provided to this program      // validate & parse arguments provided to this program
     if (argc < 3) {  
         printUsage();  
         return EXIT_FAILURE;  
     }  
540      int iArg;      int iArg;
541      for (iArg = 1; iArg < argc; ++iArg) {      for (iArg = 1; iArg < argc; ++iArg) {
542          const string opt = argv[iArg];          const string opt = argv[iArg];
# Line 511  int main(int argc, char *argv[]) { Line 560  int main(int argc, char *argv[]) {
560              return EXIT_FAILURE;              return EXIT_FAILURE;
561          }          }
562      }      }
563        if (argc < 3) {
564            printUsage();
565            return EXIT_FAILURE;
566        }
567    
568      set<string> inFileNames;      set<string> inFileNames;
569      string outFileName;      string outFileName;
# Line 571  int main(int argc, char *argv[]) { Line 624  int main(int argc, char *argv[]) {
624                  Korg::KMPInstrument* kmpInstr = *itInstr;                  Korg::KMPInstrument* kmpInstr = *itInstr;
625                  cout << "    |---> KMP multi sample '" << kmpInstr->Name() << "'" << endl;                  cout << "    |---> KMP multi sample '" << kmpInstr->Name() << "'" << endl;
626    
627                  int iLowKey = 0;                  uint16_t iLowKey = 0;
628                  for (int k = 0; k < kmpInstr->GetRegionCount(); ++k) {                  for (int k = 0; k < kmpInstr->GetRegionCount(); ++k) {
629                      Korg::KMPRegion* kmpRegion = kmpInstr->GetRegion(k);                      Korg::KMPRegion* kmpRegion = kmpInstr->GetRegion(k);
630                      DLS::range_t keyRange = { iLowKey, kmpRegion->TopKey };                      DLS::range_t keyRange = { iLowKey, kmpRegion->TopKey };
# Line 597  int main(int argc, char *argv[]) { Line 650  int main(int argc, char *argv[]) {
650                              dim.dimension = gig::dimension_samplechannel;                              dim.dimension = gig::dimension_samplechannel;
651                              dim.bits  = 1; // 2^(1) = 2                              dim.bits  = 1; // 2^(1) = 2
652                              dim.zones = 2; // stereo = 2 audio channels = 2 split zones                              dim.zones = 2; // stereo = 2 audio channels = 2 split zones
653                                cout << "Adding stereo dimension." << endl;
654                              gigRegion->AddDimension(&dim);                              gigRegion->AddDimension(&dim);
655    
656                              iStereoDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_samplechannel);                              iStereoDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_samplechannel);
# Line 613  int main(int argc, char *argv[]) { Line 667  int main(int argc, char *argv[]) {
667                      DLS::range_t velRange = { 0 , 127 };                      DLS::range_t velRange = { 0 , 127 };
668                      bool isVelocitySplit = bInterpretNames && hasNumberRangeIndicator(kmpInstr->Name());                      bool isVelocitySplit = bInterpretNames && hasNumberRangeIndicator(kmpInstr->Name());
669                      if (isVelocitySplit) { // a velocity split is required for this region ...                      if (isVelocitySplit) { // a velocity split is required for this region ...
670                          // get the amount of velocity split zones for this                          // get the set of velocity split zones defined for
671                          // particular output instrument and key range                          // this particular output instrument and key range
672                          const set<DLS::range_t> velocitySplits = collectVelocitySplits(group, keyRange);                          set<DLS::range_t> origVelocitySplits = collectVelocitySplits(group, keyRange);
673                            // if there are any gaps, that is if the list of velocity
674                          // get the velocity range for current KORG region                          // split ranges do not cover the full range completely
675                            // between 0 .. 127, then auto correct it by increasing
676                            // the split zones accordingly
677                            map<DLS::range_t,DLS::range_t> velocityCorrectionMap; // maps original defined velocity range (key) -> corrected velocity range (value)
678                          {                          {
679                              int from, to;                              set<DLS::range_t> correctedSplits;
680                              if (parseNumberRange(kmpInstr->Name(), from, to) == kmpInstr->Name())                              velocityCorrectionMap = killGapsInRanges(origVelocitySplits, correctedSplits);
681                                  throw Korg::Exception("Internal error: parsing velocity range failed");                              if (correctedSplits != origVelocitySplits) {
682                              velRange.low  = from;                                  cout << "WARNING: Velocity splits did not cover the full range 0..127, auto adjusted it from " << flush;
683                              velRange.high = to;                                  printRanges(origVelocitySplits);
684                                    cout << " to " << flush;
685                                    printRanges(correctedSplits);
686                                    cout << endl;
687                                }
688                          }                          }
689    
690                          // create velocity split dimension if it doesn't exist already ...                          // only create a velocity dimension if there was really
691                          iVelocityDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_velocity);                          // more than one velocity split zone defined
692                          if (iVelocityDimensionIndex < 0) {                          if (origVelocitySplits.size() <= 1) {
693                              gig::dimension_def_t dim;                              cerr << "WARNING: Velocity split mentioned, but with only one zone, thus ignoring velocity split.\n";
694                              dim.dimension = gig::dimension_velocity;                          } else {
695                              dim.zones = velocitySplits.size();                              // get the velocity range for current KORG region
696                                {
697                              // Find the number of bits required to hold the                                  int from, to;
698                              // specified amount of zones.                                  if (parseNumberRange(kmpInstr->Name(), from, to) == kmpInstr->Name())
699                              int zoneBits = dim.zones - 1;                                      throw Korg::Exception("Internal error: parsing velocity range failed");
700                              for (dim.bits = 0; zoneBits > 1; dim.bits += 2, zoneBits >>= 2);                                  velRange.low  = from;
701                              dim.bits += zoneBits;                                  velRange.high = to;
702                                    if (velocityCorrectionMap.find(velRange) == velocityCorrectionMap.end())
703                                        throw Korg::Exception("Internal error: inconsistency in velocity split correction map");
704                                    velRange = velocityCorrectionMap[velRange]; // corrected
705                                }
706    
707                              gigRegion->AddDimension(&dim);                              // create velocity split dimension if it doesn't exist already ...
                               
708                              iVelocityDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_velocity);                              iVelocityDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_velocity);
709                          }                              if (iVelocityDimensionIndex < 0) {
710                                    gig::dimension_def_t dim;
711                                    dim.dimension = gig::dimension_velocity;
712                                    dim.zones = origVelocitySplits.size();
713                                    // Find the number of bits required to hold the
714                                    // specified amount of zones.
715                                    int zoneBits = dim.zones - 1;
716                                    for (dim.bits = 0; zoneBits > 1; dim.bits += 2, zoneBits >>= 2);
717                                    dim.bits += zoneBits;
718                                    cout << "Adding velocity dimension: zones=" << (int)dim.zones << ", bits=" << (int)dim.bits << endl;
719                                    gigRegion->AddDimension(&dim);
720    
721                          if (iVelocityDimensionIndex < 0)                                  iVelocityDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_velocity);
722                              throw gig::Exception("Internal error: Could not resolve target velocity dimension bit");                              }
723    
724                          // find the velocity zone for this one                              if (iVelocityDimensionIndex < 0)
725                          int iVelocitySplitZone = -1;                                  throw gig::Exception("Internal error: Could not resolve target velocity dimension bit");
726                          {  
727                              int i = 0;                              // find the velocity zone for this one
728                              for (set<DLS::range_t>::const_iterator itVelSplit = velocitySplits.begin();                              int iVelocitySplitZone = -1;
                                  itVelSplit != velocitySplits.end(); ++itVelSplit, ++i)  
729                              {                              {
730                                  if (*itVelSplit == velRange) {                                  int i = 0;
731                                      iVelocitySplitZone = i;                                  for (map<DLS::range_t,DLS::range_t>::const_iterator itVelSplit = velocityCorrectionMap.begin();
732                                      break;                                      itVelSplit != velocityCorrectionMap.end(); ++itVelSplit, ++i)
733                                    {
734                                        if (itVelSplit->second == velRange) { // already corrected before, thus second, not first
735                                            iVelocitySplitZone = i;
736                                            break;
737                                        }
738                                  }                                  }
739                                    if (iVelocitySplitZone == -1)
740                                        throw gig::Exception("Internal error: Could not resolve target velocity dimension zone");
741                              }                              }
                             if (iVelocitySplitZone == -1)  
                                 throw gig::Exception("Internal error: Could not resolve target velocity dimension zone");  
                         }  
742    
743                          // select dimension bit for this stereo dimension split                              // select dimension bit for this stereo dimension split
744                          iDimBits[iVelocityDimensionIndex] = iVelocitySplitZone;                              iDimBits[iVelocityDimensionIndex] = iVelocitySplitZone;
745                            }
746                      }                      }
747    
748                      // resolve target gig::DimensionRegion for the left/right and velocity split zone detected above                      // resolve target gig::DimensionRegion for the left/right and velocity split zone detected above
# Line 678  int main(int argc, char *argv[]) { Line 756  int main(int argc, char *argv[]) {
756                          dimRgn->DimensionUpperLimits[iVelocityDimensionIndex] = velRange.high; // gig v3 and above                          dimRgn->DimensionUpperLimits[iVelocityDimensionIndex] = velRange.high; // gig v3 and above
757                      }                      }
758    
759                        dimRgn->FineTune = kmpRegion->Tune;
760    
761                      // assign the respective gig sample to this dimension region                      // assign the respective gig sample to this dimension region
762                      gig::Sample* gigSample = findOrCreateGigSampleForKSFRegion(kmpRegion);                      gig::Sample* gigSample = findOrCreateGigSampleForKSFRegion(kmpRegion);
763                      dimRgn->pSample = gigSample; // might be NULL (if Korg sample had zero size)                      dimRgn->pSample = gigSample; // might be NULL (if Korg sample had zero size, or if the original instrument's internal samples were used)
764                      if (gigSample) {                      if (gigSample) {
765                          dimRgn->UnityNote = gigSample->MIDIUnityNote;                          dimRgn->UnityNote = gigSample->MIDIUnityNote;
766                          if (gigSample->Loops) {                          if (gigSample->Loops) {

Legend:
Removed from v.2543  
changed lines
  Added in v.3175

  ViewVC Help
Powered by ViewVC