15 |
#include <set> |
#include <set> |
16 |
#include <iostream> |
#include <iostream> |
17 |
#include <assert.h> |
#include <assert.h> |
18 |
|
#include <stdarg.h> |
19 |
|
#include <string.h> |
20 |
|
|
21 |
#include <glibmm/ustring.h> |
#include <glibmm/ustring.h> |
22 |
#include <gtkmm/stock.h> |
#include <gtkmm/stock.h> |
34 |
|
|
35 |
typedef std::map<gig::dimension_t, int> DimensionRegionUpperLimits; |
typedef std::map<gig::dimension_t, int> DimensionRegionUpperLimits; |
36 |
|
|
37 |
|
typedef std::set<Glib::ustring> Warnings; |
38 |
|
|
39 |
|
/////////////////////////////////////////////////////////////////////////// |
40 |
|
// private static data |
41 |
|
|
42 |
|
static Warnings g_warnings; |
43 |
|
|
44 |
/////////////////////////////////////////////////////////////////////////// |
/////////////////////////////////////////////////////////////////////////// |
45 |
// private functions |
// private functions |
46 |
|
|
56 |
#endif |
#endif |
57 |
|
|
58 |
/** |
/** |
59 |
|
* Store a warning message that shall be stored and displayed to the user as a |
60 |
|
* list of warnings after the overall operation has finished. Duplicate warning |
61 |
|
* messages are automatically eliminated. |
62 |
|
*/ |
63 |
|
inline void addWarning(const char* fmt, ...) { |
64 |
|
va_list arg; |
65 |
|
va_start(arg, fmt); |
66 |
|
const int SZ = 255 + strlen(fmt); |
67 |
|
char* buf = new char[SZ]; |
68 |
|
vsnprintf(buf, SZ, fmt, arg); |
69 |
|
Glib::ustring s = buf; |
70 |
|
delete [] buf; |
71 |
|
va_end(arg); |
72 |
|
std::cerr << _("WARNING:") << " " << s << std::endl << std::flush; |
73 |
|
g_warnings.insert(s); |
74 |
|
} |
75 |
|
|
76 |
|
/** |
77 |
* If the two ranges overlap, then this function returns the smallest point |
* If the two ranges overlap, then this function returns the smallest point |
78 |
* within that overlapping zone. If the two ranges do not overlap, then this |
* within that overlapping zone. If the two ranges do not overlap, then this |
79 |
* function will return -1 instead. |
* function will return -1 instead. |
158 |
std::vector<gig::Region*> v = getAllRegionsWhichOverlapRange(instr, range); |
std::vector<gig::Region*> v = getAllRegionsWhichOverlapRange(instr, range); |
159 |
if (v.empty()) continue; |
if (v.empty()) continue; |
160 |
if (v.size() > 1) { |
if (v.size() > 1) { |
161 |
std::cerr << "WARNING: More than one region found!" << std::endl; |
addWarning("More than one region found!"); |
162 |
} |
} |
163 |
group[instr] = v[0]; |
group[instr] = v[0]; |
164 |
} |
} |
202 |
if (!group.empty()) |
if (!group.empty()) |
203 |
groups[range] = group; |
groups[range] = group; |
204 |
else |
else |
205 |
std::cerr << "WARNING: empty region group!" << std::endl; |
addWarning("Empty region group!"); |
206 |
} |
} |
207 |
|
|
208 |
return groups; |
return groups; |
511 |
if (inRgn->GetDimensionDefinition(gig::dimension_velocity)) { |
if (inRgn->GetDimensionDefinition(gig::dimension_velocity)) { |
512 |
DimensionZones srcZones = preciseDimensionZonesFor(gig::dimension_velocity, srcDimRgn); |
DimensionZones srcZones = preciseDimensionZonesFor(gig::dimension_velocity, srcDimRgn); |
513 |
e.totalSrcVelocityZones = srcZones.size(); |
e.totalSrcVelocityZones = srcZones.size(); |
514 |
assert(srcZones.size() > 1); |
assert(srcZones.size() > 0); |
515 |
|
if (srcZones.size() <= 1) { |
516 |
|
addWarning("Input region has a velocity dimension with only ONE zone!"); |
517 |
|
} |
518 |
if (uint(iZoneIndex) >= srcZones.size()) |
if (uint(iZoneIndex) >= srcZones.size()) |
519 |
iZoneIndex = srcZones.size() - 1; |
iZoneIndex = srcZones.size() - 1; |
520 |
srcDimCase[gig::dimension_velocity] = srcZones[iZoneIndex].low; // same zone as used above for target dimension region (no matter what the precise zone ranges are) |
srcDimCase[gig::dimension_velocity] = srcZones[iZoneIndex].low; // same zone as used above for target dimension region (no matter what the precise zone ranges are) |
590 |
// allowed to differ for individual DimensionRegions in gig v3 |
// allowed to differ for individual DimensionRegions in gig v3 |
591 |
// format |
// format |
592 |
if (srcUpperLimits.count(gig::dimension_velocity)) { |
if (srcUpperLimits.count(gig::dimension_velocity)) { |
593 |
assert(dstUpperLimits.count(gig::dimension_velocity)); |
if (!dstUpperLimits.count(gig::dimension_velocity)) { |
594 |
dstUpperLimits[gig::dimension_velocity] = |
addWarning("Source instrument seems to have a velocity dimension whereas new target instrument doesn't!"); |
595 |
(e.velocityZone >= e.totalSrcVelocityZones) |
} else { |
596 |
? 127 : srcUpperLimits[gig::dimension_velocity]; |
dstUpperLimits[gig::dimension_velocity] = |
597 |
|
(e.velocityZone >= e.totalSrcVelocityZones) |
598 |
|
? 127 : srcUpperLimits[gig::dimension_velocity]; |
599 |
|
} |
600 |
} |
} |
601 |
restoreDimensionRegionUpperLimits(e.dst, dstUpperLimits); |
restoreDimensionRegionUpperLimits(e.dst, dstUpperLimits); |
602 |
} |
} |
651 |
{ |
{ |
652 |
gig::Region* outRgn = outInstr->AddRegion(); |
gig::Region* outRgn = outInstr->AddRegion(); |
653 |
outRgn->SetKeyRange(itGroup->first.low, itGroup->first.high); |
outRgn->SetKeyRange(itGroup->first.low, itGroup->first.high); |
654 |
|
#if DEBUG_COMBINE_INSTRUMENTS |
655 |
|
printf("---> Start target region %d..%d\n", itGroup->first.low, itGroup->first.high); |
656 |
|
#endif |
657 |
|
|
658 |
// detect the total amount of layers required to build up this combi |
// detect the total amount of layers required to build up this combi |
659 |
// for current key range |
// for current key range |
664 |
gig::Region* inRgn = itRgn->second; |
gig::Region* inRgn = itRgn->second; |
665 |
iTotalLayers += inRgn->Layers; |
iTotalLayers += inRgn->Layers; |
666 |
} |
} |
667 |
|
#if DEBUG_COMBINE_INSTRUMENTS |
668 |
|
printf("Required total layers: %d\n", iTotalLayers); |
669 |
|
#endif |
670 |
|
|
671 |
// create all required dimensions for this output region |
// create all required dimensions for this output region |
672 |
// (except the layer dimension, which we create as next step) |
// (except the layer dimension, which we create as next step) |
673 |
Dimensions dims = getDimensionsForRegionGroup(itGroup->second); |
Dimensions dims = getDimensionsForRegionGroup(itGroup->second); |
|
for (Dimensions::iterator itDim = dims.begin(); |
|
|
itDim != dims.end(); ++itDim) |
|
674 |
{ |
{ |
675 |
if (itDim->first == gig::dimension_layer) continue; |
std::vector<gig::dimension_t> skipTheseDimensions; // used to prevent a misbehavior (i.e. crash) of the combine algorithm in case one of the source instruments has a dimension with only one zone, which is not standard conform |
676 |
|
|
677 |
gig::dimension_def_t def; |
for (Dimensions::iterator itDim = dims.begin(); |
678 |
def.dimension = itDim->first; // dimension type |
itDim != dims.end(); ++itDim) |
679 |
def.zones = itDim->second.size(); |
{ |
680 |
def.bits = zoneCountToBits(def.zones); |
// layer dimension is created separately in the next code block |
681 |
#if DEBUG_COMBINE_INSTRUMENTS |
// (outside of this loop) |
682 |
std::cout << "Adding new regular dimension type=" << std::hex << (int)def.dimension << std::dec << ", zones=" << (int)def.zones << ", bits=" << (int)def.bits << " ... " << std::flush; |
if (itDim->first == gig::dimension_layer) continue; |
683 |
#endif |
|
684 |
outRgn->AddDimension(&def); |
gig::dimension_def_t def; |
685 |
#if DEBUG_COMBINE_INSTRUMENTS |
def.dimension = itDim->first; // dimension type |
686 |
std::cout << "OK" << std::endl << std::flush; |
def.zones = itDim->second.size(); |
687 |
#endif |
def.bits = zoneCountToBits(def.zones); |
688 |
|
if (def.zones < 2) { |
689 |
|
addWarning( |
690 |
|
"Attempt to create dimension with type=0x%x with only " |
691 |
|
"ONE zone (because at least one of the source " |
692 |
|
"instruments seems to have such a velocity dimension " |
693 |
|
"with only ONE zone, which is odd)! Skipping this " |
694 |
|
"dimension for now.", |
695 |
|
(int)itDim->first |
696 |
|
); |
697 |
|
skipTheseDimensions.push_back(itDim->first); |
698 |
|
continue; |
699 |
|
} |
700 |
|
#if DEBUG_COMBINE_INSTRUMENTS |
701 |
|
std::cout << "Adding new regular dimension type=" << std::hex << (int)def.dimension << std::dec << ", zones=" << (int)def.zones << ", bits=" << (int)def.bits << " ... " << std::flush; |
702 |
|
#endif |
703 |
|
outRgn->AddDimension(&def); |
704 |
|
#if DEBUG_COMBINE_INSTRUMENTS |
705 |
|
std::cout << "OK" << std::endl << std::flush; |
706 |
|
#endif |
707 |
|
} |
708 |
|
// prevent the following dimensions to be processed further below |
709 |
|
// (since the respective dimension was not created above) |
710 |
|
for (int i = 0; i < skipTheseDimensions.size(); ++i) |
711 |
|
dims.erase(skipTheseDimensions[i]); |
712 |
} |
} |
713 |
|
|
714 |
// create the layer dimension (if necessary for current key range) |
// create the layer dimension (if necessary for current key range) |
732 |
itRgn != itGroup->second.end(); ++itRgn) // iterate over 'vertical' / source regions ... |
itRgn != itGroup->second.end(); ++itRgn) // iterate over 'vertical' / source regions ... |
733 |
{ |
{ |
734 |
gig::Region* inRgn = itRgn->second; |
gig::Region* inRgn = itRgn->second; |
735 |
|
#if DEBUG_COMBINE_INSTRUMENTS |
736 |
|
printf("[source region of '%s']\n", inRgn->GetParent()->pInfo->Name.c_str()); |
737 |
|
#endif |
738 |
for (uint iSrcLayer = 0; iSrcLayer < inRgn->Layers; ++iSrcLayer, ++iDstLayer) { |
for (uint iSrcLayer = 0; iSrcLayer < inRgn->Layers; ++iSrcLayer, ++iDstLayer) { |
739 |
copyDimensionRegions(outRgn, inRgn, dims, iDstLayer, iSrcLayer); |
copyDimensionRegions(outRgn, inRgn, dims, iDstLayer, iSrcLayer); |
740 |
} |
} |
850 |
instruments.push_back(instrument); |
instruments.push_back(instrument); |
851 |
} |
} |
852 |
|
|
853 |
|
g_warnings.clear(); |
854 |
|
|
855 |
try { |
try { |
856 |
combineInstruments(instruments, m_gig, m_newCombinedInstrument); |
combineInstruments(instruments, m_gig, m_newCombinedInstrument); |
857 |
} catch (RIFF::Exception e) {; |
} catch (RIFF::Exception e) {; |
860 |
return; |
return; |
861 |
} |
} |
862 |
|
|
863 |
|
if (!g_warnings.empty()) { |
864 |
|
Glib::ustring txt = _( |
865 |
|
"Combined instrument was created successfully, but there were warnings:" |
866 |
|
); |
867 |
|
txt += "\n\n"; |
868 |
|
for (Warnings::const_iterator itWarn = g_warnings.begin(); |
869 |
|
itWarn != g_warnings.end(); ++itWarn) |
870 |
|
{ |
871 |
|
txt += "-> " + *itWarn + "\n"; |
872 |
|
} |
873 |
|
txt += "\n"; |
874 |
|
txt += _( |
875 |
|
"You might also want to check the console for further warnings and " |
876 |
|
"error messages." |
877 |
|
); |
878 |
|
Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_WARNING); |
879 |
|
msg.run(); |
880 |
|
} |
881 |
|
|
882 |
// no error occurred |
// no error occurred |
883 |
m_fileWasChanged = true; |
m_fileWasChanged = true; |
884 |
hide(); |
hide(); |