fork(1) download
  1. #include <cstdint>
  2. #include <set>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <functional>
  6. #include <vector>
  7.  
  8. template<typename T>
  9. using CustomComparatorSet = std::set<T, std::function<bool (T const &, T const &)>>;
  10.  
  11. #define ITERABLE_BASED_ON(container) \
  12. auto begin () noexcept { return container.begin (); } \
  13. auto end () noexcept { return container.end (); } \
  14. auto begin () const noexcept { return container.cbegin(); } \
  15. auto end () const noexcept { return container.cend (); } \
  16. auto cbegin() const noexcept { return container.cbegin(); } \
  17. auto cend () const noexcept { return container.cend (); }
  18.  
  19. template<typename FwdIter, typename Func>
  20. Func for_each_overlapping_adjacent_pair(FwdIter a_ItBegin, FwdIter a_ItEnd, Func a_Func)
  21. {
  22. if(a_ItBegin == a_ItEnd)
  23. {
  24. return a_Func;
  25. }
  26.  
  27. FwdIter itNext = a_ItBegin;
  28. ++itNext;
  29.  
  30. while (itNext != a_ItEnd)
  31. {
  32. a_Func(*(a_ItBegin++), *(itNext++));
  33. }
  34.  
  35. return a_Func;
  36. }
  37.  
  38. struct SimpleNote
  39. {
  40. char m_Letter;
  41. uint32_t m_DurationTU;
  42. };
  43.  
  44. struct SimpleNoteEvent
  45. {
  46. uint64_t m_StartTU;
  47. SimpleNote m_Note;
  48. };
  49.  
  50. class MonophonicPart final
  51. {
  52. friend class MonophonicPartBuilder;
  53.  
  54. MonophonicPart()
  55. : m_Notes {}
  56. , m_NoteSet { [] (SimpleNoteEvent const * a_LHS, SimpleNoteEvent const * a_RHS)
  57. { return a_LHS->m_StartTU < a_RHS->m_StartTU; } }
  58. {}
  59.  
  60. public:
  61.  
  62. ITERABLE_BASED_ON(m_Notes)
  63.  
  64. // TODO: replace with std::optional
  65. std::pair<bool, SimpleNoteEvent const &> getNoteAt(uint64_t a_TU)
  66. {
  67. // Get first note that goes after selection
  68. SimpleNoteEvent dummy{ a_TU, SimpleNote{ } };
  69. auto it = m_NoteSet.upper_bound(&dummy);
  70.  
  71. if (it == m_NoteSet.begin())
  72. {
  73. // Selection goes before the first note in the part
  74. return std::make_pair(false, dummy);
  75. }
  76.  
  77. SimpleNoteEvent const & event = *(*(--it));
  78.  
  79. if (event.m_StartTU + event.m_Note.m_DurationTU > a_TU)
  80. {
  81. // Using make_pair introduces a temp obj that mess the & up
  82. return { true, event };
  83. }
  84. else
  85. {
  86. return std::make_pair(false, dummy);
  87. }
  88. }
  89.  
  90. uint64_t getLengthTU()
  91. {
  92. if (m_NoteSet.empty())
  93. {
  94. return 0;
  95. }
  96. SimpleNoteEvent const * event = *m_NoteSet.rbegin();
  97. return event->m_StartTU + event->m_Note.m_DurationTU;
  98. }
  99.  
  100. private:
  101. // Primary storage
  102. std::vector<SimpleNoteEvent> m_Notes;
  103.  
  104. // Used for quicker access to notes based on a timeunit value
  105. CustomComparatorSet<SimpleNoteEvent const *> m_NoteSet;
  106. };
  107.  
  108. class MonophonicPartBuilder final
  109. {
  110. public:
  111. MonophonicPartBuilder()
  112. : m_Notes { }
  113. , m_CurrTU { 0 }
  114. {}
  115.  
  116. void addNote(char a_Letter, uint32_t a_DurationTU)
  117. {
  118. m_Notes.emplace_back(SimpleNoteEvent{ m_CurrTU, SimpleNote{ a_Letter, a_DurationTU } });
  119. m_CurrTU += a_DurationTU;
  120. }
  121.  
  122. void addRest(uint32_t a_DurationTU)
  123. {
  124. m_CurrTU += a_DurationTU;
  125. }
  126.  
  127. MonophonicPart build()
  128. {
  129. MonophonicPart out;
  130.  
  131. // Create note set for fast timeunit-based search
  132. for (auto const & note : m_Notes)
  133. {
  134. out.m_NoteSet.insert(&note);
  135. }
  136.  
  137. // Exchange our full note vector for an empty one
  138. out.m_Notes.swap(m_Notes);
  139.  
  140. // Start back at 0 for the next build
  141. m_CurrTU = 0;
  142.  
  143. // TODO: Verify that the returning value is moved
  144. return out;
  145. }
  146.  
  147. private:
  148. std::vector<SimpleNoteEvent> m_Notes;
  149. uint64_t m_CurrTU;
  150. };
  151.  
  152. int main()
  153. {
  154. MonophonicPartBuilder builder;
  155.  
  156. builder.addRest( 16 );
  157. builder.addNote('A', 32 );
  158. builder.addRest( 32 );
  159. builder.addNote('C', 32 );
  160. builder.addNote('G', 16 );
  161. builder.addRest( 32 );
  162. builder.addRest( 32 );
  163. builder.addNote('F', 164);
  164.  
  165. MonophonicPart part = builder.build();
  166.  
  167. for (SimpleNoteEvent const & noteEvent : part)
  168. {
  169. std::cout << noteEvent.m_StartTU << " "
  170. << noteEvent.m_Note.m_Letter << " "
  171. << noteEvent.m_Note.m_DurationTU << std::endl;
  172. }
  173.  
  174. std::cout << "Length: " << part.getLengthTU() << std::endl;
  175.  
  176. std::vector<uint64_t> timeunits { 3, 15, 16, 17, 52, 87, 300, 10000 };
  177. for (uint64_t tu : timeunits)
  178. {
  179. auto result = part.getNoteAt(tu);
  180. std::cout << "At " << tu << ": ";
  181. if (result.first)
  182. std::cout << result.second.m_Note.m_Letter;
  183. else
  184. std::cout << "No note";
  185. std::cout << std::endl;
  186. }
  187.  
  188. std::multiset<int8_t> intervalSet;
  189.  
  190. for_each_overlapping_adjacent_pair(std::cbegin(part), std::cend(part),
  191. [&intervalSet] (SimpleNoteEvent const & a_First,
  192. SimpleNoteEvent const & a_Second)
  193. {
  194. intervalSet.insert(static_cast<int8_t>(a_Second.m_Note.m_Letter - a_First.m_Note.m_Letter));
  195. });
  196.  
  197. for (int8_t interval : intervalSet)
  198. {
  199. std::cout << static_cast<int32_t>(interval) << " ";
  200. }
  201.  
  202. }
Success #stdin #stdout 0s 15248KB
stdin
Standard input is empty
stdout
16 A 32
80 C 32
112 G 16
192 F 164
Length: 356
At 3: No note
At 15: No note
At 16: A
At 17: A
At 52: No note
At 87: C
At 300: F
At 10000: No note
-1 2 4