/Source/Glissando/Modified MIDI Toolkit/LocalSequencer.cs

http://glissando.codeplex.com · C# · 391 lines · 306 code · 85 blank · 0 comment · 27 complexity · 46a238d9336033788c7b68de9d4be026 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using Sanford.Multimedia.Midi;
  5. namespace Glissando
  6. {
  7. public class SequencerModified : IComponent
  8. {
  9. private Sequence sequence = null;
  10. private List<IEnumerator<int>> enumerators = new List<IEnumerator<int>>();
  11. private MessageDispatcher dispatcher = new MessageDispatcher();
  12. private ChannelChaser chaser = new ChannelChaser();
  13. private ChannelStopper stopper = new ChannelStopper();
  14. private MidiInternalClockModified clock = new MidiInternalClockModified();
  15. private int tracksPlayingCount;
  16. private readonly object lockObject = new object();
  17. private bool playing = false;
  18. private bool disposed = false;
  19. private ISite site = null;
  20. public MidiInternalClockModified Clock { get { return clock; } }
  21. #region Events
  22. public event EventHandler PlayingCompleted;
  23. public event EventHandler<ChannelMessageEventArgs> ChannelMessagePlayed
  24. {
  25. add
  26. {
  27. dispatcher.ChannelMessageDispatched += value;
  28. }
  29. remove
  30. {
  31. dispatcher.ChannelMessageDispatched -= value;
  32. }
  33. }
  34. public event EventHandler<SysExMessageEventArgs> SysExMessagePlayed
  35. {
  36. add
  37. {
  38. dispatcher.SysExMessageDispatched += value;
  39. }
  40. remove
  41. {
  42. dispatcher.SysExMessageDispatched -= value;
  43. }
  44. }
  45. public event EventHandler<MetaMessageEventArgs> MetaMessagePlayed
  46. {
  47. add
  48. {
  49. dispatcher.MetaMessageDispatched += value;
  50. }
  51. remove
  52. {
  53. dispatcher.MetaMessageDispatched -= value;
  54. }
  55. }
  56. public event EventHandler<ChasedEventArgs> Chased
  57. {
  58. add
  59. {
  60. chaser.Chased += value;
  61. }
  62. remove
  63. {
  64. chaser.Chased -= value;
  65. }
  66. }
  67. public event EventHandler<StoppedEventArgs> Stopped
  68. {
  69. add
  70. {
  71. stopper.Stopped += value;
  72. }
  73. remove
  74. {
  75. stopper.Stopped -= value;
  76. }
  77. }
  78. #endregion
  79. public SequencerModified()
  80. {
  81. clock.Tempo = 5000000; // microseconds per beat
  82. dispatcher.MetaMessageDispatched += delegate(object sender, MetaMessageEventArgs e)
  83. {
  84. if(e.Message.MetaType == MetaType.EndOfTrack)
  85. {
  86. tracksPlayingCount--;
  87. if(tracksPlayingCount == 0)
  88. {
  89. Stop();
  90. OnPlayingCompleted(EventArgs.Empty);
  91. }
  92. }
  93. else
  94. {
  95. clock.Process(e.Message);
  96. }
  97. };
  98. dispatcher.ChannelMessageDispatched += delegate(object sender, ChannelMessageEventArgs e)
  99. {
  100. stopper.Process(e.Message);
  101. };
  102. clock.Tick += delegate(object sender, EventArgs e)
  103. {
  104. lock(lockObject)
  105. {
  106. if(!playing)
  107. {
  108. return;
  109. }
  110. foreach(IEnumerator<int> enumerator in enumerators)
  111. {
  112. enumerator.MoveNext();
  113. }
  114. }
  115. };
  116. }
  117. ~SequencerModified()
  118. {
  119. Dispose(false);
  120. }
  121. protected virtual void Dispose(bool disposing)
  122. {
  123. if(disposing)
  124. {
  125. lock(lockObject)
  126. {
  127. Stop();
  128. clock.Dispose();
  129. disposed = true;
  130. GC.SuppressFinalize(this);
  131. }
  132. }
  133. }
  134. public void Start()
  135. {
  136. #region Require
  137. if(disposed)
  138. {
  139. throw new ObjectDisposedException(this.GetType().Name);
  140. }
  141. #endregion
  142. lock(lockObject)
  143. {
  144. Stop();
  145. Position = 0;
  146. Continue();
  147. }
  148. }
  149. public void Continue()
  150. {
  151. #region Require
  152. if(disposed)
  153. {
  154. throw new ObjectDisposedException(this.GetType().Name);
  155. }
  156. #endregion
  157. #region Guard
  158. if(Sequence == null)
  159. {
  160. return;
  161. }
  162. #endregion
  163. lock(lockObject)
  164. {
  165. Stop();
  166. enumerators.Clear();
  167. foreach(Track t in Sequence)
  168. {
  169. enumerators.Add(t.TickIterator(Position, chaser, dispatcher).GetEnumerator());
  170. }
  171. tracksPlayingCount = Sequence.Count;
  172. playing = true;
  173. clock.Ppqn = sequence.Division;
  174. clock.Continue();
  175. }
  176. }
  177. public void Stop()
  178. {
  179. #region Require
  180. if(disposed)
  181. {
  182. throw new ObjectDisposedException(this.GetType().Name);
  183. }
  184. #endregion
  185. lock(lockObject)
  186. {
  187. #region Guard
  188. if(!playing)
  189. {
  190. return;
  191. }
  192. #endregion
  193. playing = false;
  194. clock.Stop();
  195. stopper.AllSoundOff();
  196. }
  197. }
  198. protected virtual void OnPlayingCompleted(EventArgs e)
  199. {
  200. EventHandler handler = PlayingCompleted;
  201. if(handler != null)
  202. {
  203. handler(this, e);
  204. }
  205. }
  206. protected virtual void OnDisposed(EventArgs e)
  207. {
  208. EventHandler handler = Disposed;
  209. if(handler != null)
  210. {
  211. handler(this, e);
  212. }
  213. }
  214. public int Position
  215. {
  216. get
  217. {
  218. #region Require
  219. if(disposed)
  220. {
  221. throw new ObjectDisposedException(this.GetType().Name);
  222. }
  223. #endregion
  224. return clock.Ticks;
  225. }
  226. set
  227. {
  228. #region Require
  229. if(disposed)
  230. {
  231. throw new ObjectDisposedException(this.GetType().Name);
  232. }
  233. else if(value < 0)
  234. {
  235. throw new ArgumentOutOfRangeException();
  236. }
  237. #endregion
  238. bool wasPlaying;
  239. lock(lockObject)
  240. {
  241. wasPlaying = playing;
  242. Stop();
  243. clock.SetTicks(value);
  244. }
  245. lock(lockObject)
  246. {
  247. if(wasPlaying)
  248. {
  249. Continue();
  250. }
  251. }
  252. }
  253. }
  254. public Sequence Sequence
  255. {
  256. get
  257. {
  258. return sequence;
  259. }
  260. set
  261. {
  262. #region Require
  263. if(value == null)
  264. {
  265. throw new ArgumentNullException();
  266. }
  267. else if(value.SequenceType == SequenceType.Smpte)
  268. {
  269. throw new NotSupportedException();
  270. }
  271. #endregion
  272. lock(lockObject)
  273. {
  274. Stop();
  275. sequence = value;
  276. }
  277. }
  278. }
  279. #region IComponent Members
  280. public event EventHandler Disposed;
  281. public ISite Site
  282. {
  283. get
  284. {
  285. return site;
  286. }
  287. set
  288. {
  289. site = value;
  290. }
  291. }
  292. #endregion
  293. #region IDisposable Members
  294. public void Dispose()
  295. {
  296. #region Guard
  297. if(disposed)
  298. {
  299. return;
  300. }
  301. #endregion
  302. Dispose(true);
  303. }
  304. #endregion
  305. }
  306. }