You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
6.6KB

  1. #pragma once
  2. #include <stdint.h>
  3. #include <memory>
  4. #include <assert.h>
  5. #include "asserts.h"
  6. #include "PitchUtils.h"
  7. // forward declare smart pointers
  8. class MidiEvent;
  9. class MidiEndEvent;
  10. class MidiNoteEvent;
  11. class MidiTestEvent;
  12. class MidiEndEvent;
  13. using MidiEndEventPtr = std::shared_ptr<MidiEndEvent>;
  14. using MidiTestEventPtr = std::shared_ptr<MidiTestEvent>;
  15. using MidiEventPtr = std::shared_ptr<MidiEvent>;
  16. using MidiEventPtrC = std::shared_ptr<const MidiEvent>;
  17. using MidiNoteEventPtr = std::shared_ptr<MidiNoteEvent>;
  18. using MidiNoteEventPtrC = std::shared_ptr<const MidiNoteEvent>;
  19. /**
  20. * Abstract base class for all events
  21. */
  22. class MidiEvent
  23. {
  24. public:
  25. typedef float time_t;
  26. enum class Type
  27. {
  28. Note,
  29. End,
  30. Test
  31. };
  32. Type type = Type::Test;
  33. /**
  34. * time units are floats, 1.0 == quarter note
  35. */
  36. time_t startTime = 0;
  37. bool operator == (const MidiEvent&) const;
  38. bool operator != (const MidiEvent&) const;
  39. virtual MidiEventPtr clone() const = 0;
  40. virtual void assertValid() const;
  41. virtual ~MidiEvent()
  42. {
  43. #ifdef _DEBUG
  44. --_count;
  45. #endif
  46. }
  47. #ifdef _DEBUG
  48. static int _count; // for debugging - reference count
  49. #endif
  50. protected:
  51. MidiEvent()
  52. {
  53. #ifdef _DEBUG
  54. ++_count;
  55. #endif
  56. }
  57. MidiEvent(const MidiEvent& e)
  58. {
  59. #ifdef _DEBUG
  60. ++_count;
  61. #endif
  62. this->startTime = e.startTime;
  63. }
  64. public:
  65. virtual bool isEqualBase(const MidiEvent& other) const
  66. {
  67. return this->startTime == other.startTime;
  68. }
  69. virtual bool isEqual(const MidiEvent& other) const = 0;
  70. };
  71. inline bool MidiEvent::operator == (const MidiEvent& other) const
  72. {
  73. if (other.type != this->type) {
  74. return false;
  75. }
  76. return isEqual(other);
  77. }
  78. inline bool MidiEvent::operator != (const MidiEvent& other) const
  79. {
  80. return !(*this == other);
  81. }
  82. inline void MidiEvent::assertValid() const
  83. {
  84. assertGE(startTime, 0);
  85. }
  86. /**
  87. * Derived pointers must provide an implementation for casting
  88. * base (MidiEventPtr) to derived pointer
  89. */
  90. template<typename T, typename Q>
  91. inline std::shared_ptr<T> safe_cast(std::shared_ptr<Q>)
  92. {
  93. // default implementation always fails.
  94. // this avoids linker errors for unimplemented cases
  95. return nullptr;
  96. }
  97. /********************************************************************
  98. **
  99. ** MidiNoteEvent
  100. **
  101. ********************************************************************/
  102. class MidiNoteEvent : public MidiEvent
  103. {
  104. public:
  105. MidiNoteEvent()
  106. {
  107. type = Type::Note;
  108. }
  109. MidiNoteEvent(const MidiNoteEvent& n) : MidiEvent(n)
  110. {
  111. type = Type::Note;
  112. this->pitchCV = n.pitchCV;
  113. this->duration = n.duration;
  114. }
  115. /**
  116. * Pitch is VCV standard 1V/8
  117. */
  118. float pitchCV = 0;
  119. float duration = 1;
  120. void assertValid() const override;
  121. void setPitch(int octave, int semi);
  122. std::pair<int, int> getPitch() const;
  123. virtual MidiEventPtr clone() const override;
  124. MidiNoteEventPtr clonen() const;
  125. protected:
  126. virtual bool isEqual(const MidiEvent&) const override;
  127. };
  128. inline std::pair<int, int> MidiNoteEvent::getPitch() const
  129. {
  130. return PitchUtils::cvToPitch(pitchCV);
  131. }
  132. inline void MidiNoteEvent::setPitch(int octave, int semi)
  133. {
  134. pitchCV = PitchUtils::pitchToCV(octave, semi);
  135. }
  136. inline void MidiNoteEvent::assertValid() const
  137. {
  138. MidiEvent::assertValid();
  139. assertLE(pitchCV, 10);
  140. assertGE(pitchCV, -10);
  141. assertGT(duration, 0);
  142. }
  143. inline bool MidiNoteEvent::isEqual(const MidiEvent& other) const
  144. {
  145. const MidiNoteEvent* otherNote = static_cast<const MidiNoteEvent*>(&other);
  146. return other.isEqualBase(*this) &&
  147. this->pitchCV == otherNote->pitchCV &&
  148. this->duration == otherNote->duration;
  149. }
  150. template<>
  151. inline MidiNoteEventPtr safe_cast(std::shared_ptr<MidiEvent> ev)
  152. {
  153. MidiNoteEventPtr note;
  154. if (ev->type == MidiEvent::Type::Note) {
  155. note = std::static_pointer_cast<MidiNoteEvent>(ev);
  156. }
  157. return note;
  158. }
  159. template<>
  160. inline std::shared_ptr<MidiEvent> safe_cast(std::shared_ptr<MidiNoteEvent> ev)
  161. {
  162. return ev;
  163. }
  164. inline MidiNoteEventPtr MidiNoteEvent::clonen() const
  165. {
  166. return std::make_shared<MidiNoteEvent>(*this);
  167. }
  168. inline MidiEventPtr MidiNoteEvent::clone() const
  169. {
  170. return this->clonen();
  171. }
  172. /********************************************************************
  173. **
  174. ** MidiEndEvent
  175. **
  176. ********************************************************************/
  177. class MidiEndEvent : public MidiEvent
  178. {
  179. public:
  180. void assertValid() const override;
  181. MidiEndEvent()
  182. {
  183. type = Type::End;
  184. }
  185. MidiEndEvent(const MidiEndEvent& e) : MidiEvent(e)
  186. {
  187. type = Type::End;
  188. }
  189. virtual MidiEventPtr clone() const override;
  190. MidiEndEventPtr clonee() const;
  191. protected:
  192. virtual bool isEqual(const MidiEvent&) const override;
  193. };
  194. inline void MidiEndEvent::assertValid() const
  195. {
  196. MidiEvent::assertValid();
  197. }
  198. inline bool MidiEndEvent::isEqual(const MidiEvent& other) const
  199. {
  200. //const MidiEndEvent* otherNote = static_cast<const MidiEndEvent*>(&other);
  201. return other.isEqualBase(*this);
  202. }
  203. template<>
  204. inline std::shared_ptr<MidiEndEvent> safe_cast(std::shared_ptr<MidiEvent> ev)
  205. {
  206. std::shared_ptr<MidiEndEvent> endev;
  207. if (ev->type == MidiEvent::Type::End) {
  208. endev = std::static_pointer_cast<MidiEndEvent>(ev);
  209. }
  210. return endev;
  211. }
  212. template<>
  213. inline std::shared_ptr<MidiEvent> safe_cast(std::shared_ptr<MidiEndEvent> ev)
  214. {
  215. return ev;
  216. }
  217. inline MidiEventPtr MidiEndEvent::clone() const
  218. {
  219. return std::make_shared<MidiEndEvent>(*this);
  220. }
  221. /********************************************************************
  222. **
  223. ** MidiTestEvent
  224. ** (just for unit tests)
  225. ********************************************************************/
  226. class MidiTestEvent : public MidiEvent
  227. {
  228. public:
  229. void assertValid() const override;
  230. MidiTestEvent()
  231. {
  232. type = Type::Test;
  233. }
  234. virtual MidiEventPtr clone() const override;
  235. protected:
  236. virtual bool isEqual(const MidiEvent&) const override;
  237. };
  238. inline void MidiTestEvent::assertValid() const
  239. {
  240. MidiEvent::assertValid();
  241. }
  242. inline bool MidiTestEvent::isEqual(const MidiEvent& other) const
  243. {
  244. return other.isEqualBase(*this);
  245. }
  246. template<>
  247. inline std::shared_ptr<MidiTestEvent> safe_cast(std::shared_ptr<MidiEvent> ev)
  248. {
  249. std::shared_ptr<MidiTestEvent> test;
  250. if (ev->type == MidiEvent::Type::Test) {
  251. test = std::static_pointer_cast<MidiTestEvent>(ev);
  252. }
  253. return test;
  254. }
  255. template<>
  256. inline std::shared_ptr<MidiEvent> safe_cast(std::shared_ptr<MidiTestEvent> ev)
  257. {
  258. return ev;
  259. }
  260. inline MidiEventPtr MidiTestEvent::clone() const
  261. {
  262. return std::make_shared<MidiTestEvent>(*this);
  263. }