/[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 2836 by persson, Sun Aug 23 05:57:18 2015 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2014 Christian Schoenebeck                              *   *   Copyright (C) 2014-2015 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      return haystack.substr(haystack.size() - needle.size(), needle.size()) == needle;      return haystack.substr(haystack.size() - needle.size(), needle.size()) == needle;
72  }  }
# Line 306  static set<DLS::range_t> collectVelocity Line 310  static set<DLS::range_t> collectVelocity
310      set<DLS::range_t> velocityRanges;      set<DLS::range_t> velocityRanges;
311      for (int i = 0; i < group.size(); ++i) {      for (int i = 0; i < group.size(); ++i) {
312          Korg::KMPInstrument* instr = group[i];          Korg::KMPInstrument* instr = group[i];
313          int iLowerKey = 0;          uint16_t iLowerKey = 0;
314          for (int k = 0; k < instr->GetRegionCount(); ++k) {          for (int k = 0; k < instr->GetRegionCount(); ++k) {
315              Korg::KMPRegion* rgn = instr->GetRegion(k);              Korg::KMPRegion* rgn = instr->GetRegion(k);
316              DLS::range_t keyRange2 = { iLowerKey, rgn->TopKey };              DLS::range_t keyRange2 = { iLowerKey, rgn->TopKey };
# Line 315  static set<DLS::range_t> collectVelocity Line 319  static set<DLS::range_t> collectVelocity
319                  int from, to;                  int from, to;
320                  string baseName = parseNumberRange(instr->Name(), from, to);                  string baseName = parseNumberRange(instr->Name(), from, to);
321                  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 ...
322                      DLS::range_t velRange = { from, to };                      DLS::range_t velRange = { uint16_t(from), uint16_t(to) };
323                      velocityRanges.insert(velRange);                      velocityRanges.insert(velRange);
324                  }                  }
325              }              }
# Line 324  static set<DLS::range_t> collectVelocity Line 328  static set<DLS::range_t> collectVelocity
328      return velocityRanges;      return velocityRanges;
329  }  }
330    
331    /**
332     * Ensure that the given list of ranges covers the full range between 0 .. 127.
333     *
334     * @param orig - (input) original set of ranges (read only)
335     * @param corrected - (output) corrected set of ranges (will be cleared and refilled)
336     * @return map that pairs respective original range with respective corrected range
337     */
338    static map<DLS::range_t,DLS::range_t> killGapsInRanges(const set<DLS::range_t>& orig, set<DLS::range_t>& corrected) {
339        map<DLS::range_t,DLS::range_t> result;
340        corrected.clear();
341        if (orig.empty()) return result;
342    
343        int iLow = 0;
344        int i = 0;
345        for (set<DLS::range_t>::const_iterator it = orig.begin(); it != orig.end(); ++it, ++i) {
346            DLS::range_t r = *it;
347            r.low = iLow;
348            iLow = r.high + 1;
349            if (i == orig.size() - 1) r.high = 127;
350            corrected.insert(r);
351            result[*it] = r;
352        }
353        return result;
354    }
355    
356    static void printRanges(const set<DLS::range_t>& ranges) {
357        cout << "{ ";
358        for (set<DLS::range_t>::const_iterator it = ranges.begin(); it != ranges.end(); ++it) {
359            if (it != ranges.begin()) cout << ", ";
360            cout << (int)it->low << ".." << (int)it->high;
361        }
362        cout << " }" << flush;
363    }
364    
365  static vector<Korg::KSFSample*>     ksfSamples;      // input .KSF files  static vector<Korg::KSFSample*>     ksfSamples;      // input .KSF files
366  static vector<Korg::KMPInstrument*> kmpInstruments;  // input .KMP files  static vector<Korg::KMPInstrument*> kmpInstruments;  // input .KMP files
367  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 450  static gig::Sample* findOrCreateGigSampl
450          gigSampleGroup->Name = baseName;          gigSampleGroup->Name = baseName;
451      }      }
452    
453        if (kmpRegion->SampleFileName == "SKIPPEDSAMPL" ||
454            (beginsWith(kmpRegion->SampleFileName, "INTERNAL") && !endsWith(kmpRegion->SampleFileName, ".KSF")))
455        {
456            return NULL;
457        }
458    
459      Korg::KSFSample* ksfSample = findKSFSampleWithFileName(kmpRegion->FullSampleFileName());      Korg::KSFSample* ksfSample = findKSFSampleWithFileName(kmpRegion->FullSampleFileName());
460      if (!ksfSample)      if (!ksfSample)
461          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 476  static void loadKorgFile(const string& f
476    
477              for (int i = 0; i < instr->GetRegionCount(); ++i) {              for (int i = 0; i < instr->GetRegionCount(); ++i) {
478                  Korg::KMPRegion* rgn = instr->GetRegion(i);                  Korg::KMPRegion* rgn = instr->GetRegion(i);
479                    if (rgn->SampleFileName == "SKIPPEDSAMPL") {
480                        cout << "WARNING: 'SKIPPEDSAMPL' as sample reference found!\n";
481                        continue;
482                    } else if (beginsWith(rgn->SampleFileName, "INTERNAL") &&
483                               !endsWith(rgn->SampleFileName, ".KSF")) {
484                        cout << "WARNING: One of the KORG instrument's internal samples was referenced as sample!\n";
485                        continue;
486                    }
487                  // check if the sample referenced by this region was already                  // check if the sample referenced by this region was already
488                  // loaded, if not then load it ...                  // loaded, if not then load it ...
489                  if (!findKSFSampleWithFileName(rgn->FullSampleFileName()))                  if (!findKSFSampleWithFileName(rgn->FullSampleFileName()))
# Line 484  int main(int argc, char *argv[]) { Line 536  int main(int argc, char *argv[]) {
536      bool bForce = false;      bool bForce = false;
537    
538      // validate & parse arguments provided to this program      // validate & parse arguments provided to this program
     if (argc < 3) {  
         printUsage();  
         return EXIT_FAILURE;  
     }  
539      int iArg;      int iArg;
540      for (iArg = 1; iArg < argc; ++iArg) {      for (iArg = 1; iArg < argc; ++iArg) {
541          const string opt = argv[iArg];          const string opt = argv[iArg];
# Line 511  int main(int argc, char *argv[]) { Line 559  int main(int argc, char *argv[]) {
559              return EXIT_FAILURE;              return EXIT_FAILURE;
560          }          }
561      }      }
562        if (argc < 3) {
563            printUsage();
564            return EXIT_FAILURE;
565        }
566    
567      set<string> inFileNames;      set<string> inFileNames;
568      string outFileName;      string outFileName;
# Line 571  int main(int argc, char *argv[]) { Line 623  int main(int argc, char *argv[]) {
623                  Korg::KMPInstrument* kmpInstr = *itInstr;                  Korg::KMPInstrument* kmpInstr = *itInstr;
624                  cout << "    |---> KMP multi sample '" << kmpInstr->Name() << "'" << endl;                  cout << "    |---> KMP multi sample '" << kmpInstr->Name() << "'" << endl;
625    
626                  int iLowKey = 0;                  uint16_t iLowKey = 0;
627                  for (int k = 0; k < kmpInstr->GetRegionCount(); ++k) {                  for (int k = 0; k < kmpInstr->GetRegionCount(); ++k) {
628                      Korg::KMPRegion* kmpRegion = kmpInstr->GetRegion(k);                      Korg::KMPRegion* kmpRegion = kmpInstr->GetRegion(k);
629                      DLS::range_t keyRange = { iLowKey, kmpRegion->TopKey };                      DLS::range_t keyRange = { iLowKey, kmpRegion->TopKey };
# Line 597  int main(int argc, char *argv[]) { Line 649  int main(int argc, char *argv[]) {
649                              dim.dimension = gig::dimension_samplechannel;                              dim.dimension = gig::dimension_samplechannel;
650                              dim.bits  = 1; // 2^(1) = 2                              dim.bits  = 1; // 2^(1) = 2
651                              dim.zones = 2; // stereo = 2 audio channels = 2 split zones                              dim.zones = 2; // stereo = 2 audio channels = 2 split zones
652                                cout << "Adding stereo dimension." << endl;
653                              gigRegion->AddDimension(&dim);                              gigRegion->AddDimension(&dim);
654    
655                              iStereoDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_samplechannel);                              iStereoDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_samplechannel);
# Line 613  int main(int argc, char *argv[]) { Line 666  int main(int argc, char *argv[]) {
666                      DLS::range_t velRange = { 0 , 127 };                      DLS::range_t velRange = { 0 , 127 };
667                      bool isVelocitySplit = bInterpretNames && hasNumberRangeIndicator(kmpInstr->Name());                      bool isVelocitySplit = bInterpretNames && hasNumberRangeIndicator(kmpInstr->Name());
668                      if (isVelocitySplit) { // a velocity split is required for this region ...                      if (isVelocitySplit) { // a velocity split is required for this region ...
669                          // get the amount of velocity split zones for this                          // get the set of velocity split zones defined for
670                          // particular output instrument and key range                          // this particular output instrument and key range
671                          const set<DLS::range_t> velocitySplits = collectVelocitySplits(group, keyRange);                          set<DLS::range_t> origVelocitySplits = collectVelocitySplits(group, keyRange);
672                            // if there are any gaps, that is if the list of velocity
673                          // get the velocity range for current KORG region                          // split ranges do not cover the full range completely
674                            // between 0 .. 127, then auto correct it by increasing
675                            // the split zones accordingly
676                            map<DLS::range_t,DLS::range_t> velocityCorrectionMap; // maps original defined velocity range (key) -> corrected velocity range (value)
677                          {                          {
678                              int from, to;                              set<DLS::range_t> correctedSplits;
679                              if (parseNumberRange(kmpInstr->Name(), from, to) == kmpInstr->Name())                              velocityCorrectionMap = killGapsInRanges(origVelocitySplits, correctedSplits);
680                                  throw Korg::Exception("Internal error: parsing velocity range failed");                              if (correctedSplits != origVelocitySplits) {
681                              velRange.low  = from;                                  cout << "WARNING: Velocity splits did not cover the full range 0..127, auto adjusted it from " << flush;
682                              velRange.high = to;                                  printRanges(origVelocitySplits);
683                                    cout << " to " << flush;
684                                    printRanges(correctedSplits);
685                                    cout << endl;
686                                }
687                          }                          }
688    
689                          // create velocity split dimension if it doesn't exist already ...                          // only create a velocity dimension if there was really
690                          iVelocityDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_velocity);                          // more than one velocity split zone defined
691                          if (iVelocityDimensionIndex < 0) {                          if (origVelocitySplits.size() <= 1) {
692                              gig::dimension_def_t dim;                              cerr << "WARNING: Velocity split mentioned, but with only one zone, thus ignoring velocity split.\n";
693                              dim.dimension = gig::dimension_velocity;                          } else {
694                              dim.zones = velocitySplits.size();                              // get the velocity range for current KORG region
695                                {
696                              // Find the number of bits required to hold the                                  int from, to;
697                              // specified amount of zones.                                  if (parseNumberRange(kmpInstr->Name(), from, to) == kmpInstr->Name())
698                              int zoneBits = dim.zones - 1;                                      throw Korg::Exception("Internal error: parsing velocity range failed");
699                              for (dim.bits = 0; zoneBits > 1; dim.bits += 2, zoneBits >>= 2);                                  velRange.low  = from;
700                              dim.bits += zoneBits;                                  velRange.high = to;
701                                    if (velocityCorrectionMap.find(velRange) == velocityCorrectionMap.end())
702                                        throw Korg::Exception("Internal error: inconsistency in velocity split correction map");
703                                    velRange = velocityCorrectionMap[velRange]; // corrected
704                                }
705    
706                              gigRegion->AddDimension(&dim);                              // create velocity split dimension if it doesn't exist already ...
                               
707                              iVelocityDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_velocity);                              iVelocityDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_velocity);
708                          }                              if (iVelocityDimensionIndex < 0) {
709                                    gig::dimension_def_t dim;
710                                    dim.dimension = gig::dimension_velocity;
711                                    dim.zones = origVelocitySplits.size();
712                                    // Find the number of bits required to hold the
713                                    // specified amount of zones.
714                                    int zoneBits = dim.zones - 1;
715                                    for (dim.bits = 0; zoneBits > 1; dim.bits += 2, zoneBits >>= 2);
716                                    dim.bits += zoneBits;
717                                    cout << "Adding velocity dimension: zones=" << (int)dim.zones << ", bits=" << (int)dim.bits << endl;
718                                    gigRegion->AddDimension(&dim);
719    
720                          if (iVelocityDimensionIndex < 0)                                  iVelocityDimensionIndex = getDimensionIndex(gigRegion, gig::dimension_velocity);
721                              throw gig::Exception("Internal error: Could not resolve target velocity dimension bit");                              }
722    
723                          // find the velocity zone for this one                              if (iVelocityDimensionIndex < 0)
724                          int iVelocitySplitZone = -1;                                  throw gig::Exception("Internal error: Could not resolve target velocity dimension bit");
725                          {  
726                              int i = 0;                              // find the velocity zone for this one
727                              for (set<DLS::range_t>::const_iterator itVelSplit = velocitySplits.begin();                              int iVelocitySplitZone = -1;
                                  itVelSplit != velocitySplits.end(); ++itVelSplit, ++i)  
728                              {                              {
729                                  if (*itVelSplit == velRange) {                                  int i = 0;
730                                      iVelocitySplitZone = i;                                  for (map<DLS::range_t,DLS::range_t>::const_iterator itVelSplit = velocityCorrectionMap.begin();
731                                      break;                                      itVelSplit != velocityCorrectionMap.end(); ++itVelSplit, ++i)
732                                    {
733                                        if (itVelSplit->second == velRange) { // already corrected before, thus second, not first
734                                            iVelocitySplitZone = i;
735                                            break;
736                                        }
737                                  }                                  }
738                                    if (iVelocitySplitZone == -1)
739                                        throw gig::Exception("Internal error: Could not resolve target velocity dimension zone");
740                              }                              }
                             if (iVelocitySplitZone == -1)  
                                 throw gig::Exception("Internal error: Could not resolve target velocity dimension zone");  
                         }  
741    
742                          // select dimension bit for this stereo dimension split                              // select dimension bit for this stereo dimension split
743                          iDimBits[iVelocityDimensionIndex] = iVelocitySplitZone;                              iDimBits[iVelocityDimensionIndex] = iVelocitySplitZone;
744                            }
745                      }                      }
746    
747                      // 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 680  int main(int argc, char *argv[]) { Line 757  int main(int argc, char *argv[]) {
757    
758                      // assign the respective gig sample to this dimension region                      // assign the respective gig sample to this dimension region
759                      gig::Sample* gigSample = findOrCreateGigSampleForKSFRegion(kmpRegion);                      gig::Sample* gigSample = findOrCreateGigSampleForKSFRegion(kmpRegion);
760                      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)
761                      if (gigSample) {                      if (gigSample) {
762                          dimRgn->UnityNote = gigSample->MIDIUnityNote;                          dimRgn->UnityNote = gigSample->MIDIUnityNote;
763                          if (gigSample->Loops) {                          if (gigSample->Loops) {

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

  ViewVC Help
Powered by ViewVC