#include "BeatSequence.h" #include namespace midi { BeatSequence::BeatSequence() : BeatSequence(0) { } BeatSequence::BeatSequence(BeatIndex size) : parent(size) { } void BeatSequence::expand(BeatIndex factor) { if(factor < 1) { throw "factor may not be less than 1."; } resize(size() * factor); for(signed int targetIndex = (size() - factor); targetIndex > 0; targetIndex -= factor) { BeatIndex sourceIndex = targetIndex / factor; at(sourceIndex).swap(at(targetIndex)); } } void BeatSequence::reduce(BeatIndex factor) { reduce(factor, 0, 0); } void BeatSequence::reduce(BeatIndex factor, ReductionConflictCallback conflictCallback, void* conflictCallbackData) { if(factor < 1) { throw "factor may not be less than 1."; } if(conflictCallback != 0) { for(BeatIndex beatIndex = 0; beatIndex < size(); beatIndex++) { if(beatIndex % factor != 0 && at(beatIndex).size() > 0) { conflictCallback(*this, factor, beatIndex, conflictCallbackData); } } } for(BeatIndex beatIndex = 0; beatIndex < size(); beatIndex++) { if(beatIndex % factor != 0 && at(beatIndex).size() > 0) { throw new UnresolvedBeatSequenceReductionConflict(beatIndex); } } BeatIndex targetSize = (size() + factor - 1) / factor; for(BeatIndex targetIndex = 0; targetIndex < targetSize; targetIndex++) { BeatIndex sourceIndex = targetIndex * factor; at(sourceIndex).swap(at(targetIndex)); } resize(targetSize); } void BeatSequence::print(std::ostream& stream) const { if(size() == 0) { stream << "beat sequence of length 0\n"; } else { stream << "beat sequence:\n"; for(BeatIndex beatIndex = 0; beatIndex < size(); beatIndex++) { std::stringstream beatLabelStream; beatLabelStream << "beat #" << beatIndex << ": "; std::string beatLabel = beatLabelStream.str(); stream << beatLabel; std::string spacer(beatLabel.size(), ' '); const MessageList& beat = at(beatIndex); if(beat.size() == 0) { stream << "no message" << "\n"; } else { for(MessageList::const_iterator msg_it = beat.begin(); msg_it != beat.end(); msg_it++) { if(msg_it != beat.begin()) { stream << spacer; } (*msg_it)->print(stream); } } } } stream << "\n"; stream.flush(); } void BeatSequence::reduceToNeighbour(BeatIndex factor) { reduce(factor, moveReductionConflictToNextNeighbour, 0); } void BeatSequence::reduceErasingConflicts(BeatIndex factor) { reduce(factor, eraseReductionConflict, 0); } void BeatSequence::eraseReductionConflict(BeatSequence& sequence, BeatIndex factor, BeatIndex beatIndex, void* data) { sequence.at(beatIndex).clear(); } void BeatSequence::moveReductionConflictToNextNeighbour(BeatSequence& sequence, BeatIndex factor, BeatIndex beatIndex, void* data) { BeatSequence::BeatIndex previousIndex = beatIndex / factor * factor; BeatSequence::BeatIndex targetIndex; if((beatIndex - previousIndex) * 2 <= factor) { targetIndex = previousIndex; } else { targetIndex = previousIndex + factor; if(targetIndex >= sequence.size()) { targetIndex = 0; } } MessageList& targetBeat = sequence[targetIndex]; targetBeat.splice(targetBeat.end(), sequence[beatIndex]); } UnresolvedBeatSequenceReductionConflict::UnresolvedBeatSequenceReductionConflict(BeatSequence::BeatIndex beatIndex) : parent("unresolved beat sequence reducation conflict"), beatIndex(beatIndex) { } const char* UnresolvedBeatSequenceReductionConflict::what() const throw() { std::stringstream info; info << parent::what() << " at beat #" << getBeatIndex(); return info.str().c_str(); } BeatSequence::BeatIndex UnresolvedBeatSequenceReductionConflict::getBeatIndex() const { return beatIndex; } } // namepsace