public Sequencer() { dispatcher.MetaMessageDispatched += delegate(object sender, MetaMessageEventArgs e) { if (e.Message.MetaType == MetaType.EndOfTrack) { tracksPlayingCount--; if (tracksPlayingCount == 0) { Stop(); OnPlayingCompleted(EventArgs.Empty); } } else { clock.Process(e.Message); } }; dispatcher.ChannelMessageDispatched += delegate(object sender, ChannelMessageEventArgs e) { stopper.Process(e.Message); }; clock.Tick += delegate(object sender, EventArgs e) { lock (lockObject) { if (!playing) { return; } foreach (IEnumerator <int> enumerator in enumerators) { enumerator.MoveNext(); } } }; }
public SequencerWP() { dispatcher.MetaMessageDispatched += delegate(object sender, MetaMessageEventArgs e) { if (e.Message.MetaType == MetaType.EndOfTrack) { tracksPlayingCount--; UnityEngine.Debug.LogFormat("end. t:{0}", tracksPlayingCount); if (tracksPlayingCount == 0) { Stop(true); // playing completed handles initialization if looping is enabled. OnPlayingCompleted(EventArgs.Empty); } } else { clock.Process(e.Message); } }; dispatcher.ChannelMessageDispatched += delegate(object sender, ChannelMessageEventArgs e) { stopper.Process(e.Message); }; clock.Tick += delegate(object sender, EventArgs e) { lock (lockObject) { if (!playing) { return; } if (Position == LoopEnd) { Stop(true); // playing completed handles initialization if looping is enabled. OnPlayingCompleted(EventArgs.Empty); return; } // only go through tick iterator if we are out of start offset if (Position >= LoopStart) { foreach (IEnumerator <int> enumerator in enumerators) { enumerator.MoveNext(); } } } }; sequence = GlobalReference.sequence; if (Sequence == null) { throw new Exception("Sequence should not be null."); } // Process each track and produce the queue of notes to played. This queue is the player paced sheet music. Dictionary <int, NoteWithDuration> noteToTicksTable = new Dictionary <int, NoteWithDuration>(); foreach (Track t in Sequence) { if (t.TrackId == -1) { throw new Exception("Track ID is 0. Track is not loaded correctly."); } // not part of user select track to play if (t.TrackId != GlobalReference.leftHandTrackIndex && t.TrackId != GlobalReference.rightHandTrackIndex) { continue; } noteToTicksTable.Clear(); notesList.Add(new NotesList()); int trackIndex = notesList.Count - 1; IEnumerator <MidiEvent> enumerator = t.Iterator().GetEnumerator(); while (enumerator.MoveNext()) { if (enumerator.Current.MidiMessage.MessageType != MidiMessageType.Channel) { continue; } ChannelMessage channelMsg = (ChannelMessage)enumerator.Current.MidiMessage; // Store absolute ticks of NoteOn message in hash table if (channelMsg.Command == ChannelCommand.NoteOn) { if (channelMsg.Data2 == 0) // Note on message with velocity of 0 is equivalent of Note Off Message { NoteWithDuration noteOff; if (noteToTicksTable.TryGetValue(channelMsg.Data1, out noteOff)) { //UnityEngine.Debug.LogFormat("OFF, {0}", channelMsg.Data1); noteOff.Duration = enumerator.Current.AbsoluteTicks - noteOff.AbsoluteTicks; // TODO: Test if this works noteToTicksTable.Remove(channelMsg.Data1); } } else { //UnityEngine.Debug.LogFormat("ON, {0} Ticks:{1}", channelMsg.Data1, enumerator.Current.AbsoluteTicks); if (!noteToTicksTable.ContainsKey(channelMsg.Data1)) { NoteWithDuration note = new NoteWithDuration(enumerator.Current.AbsoluteTicks, channelMsg.Data1, -1, channelMsg.MidiTrack); notesList[trackIndex].Add(ref note); noteToTicksTable.Add(channelMsg.Data1, note); } else { UnityEngine.Debug.LogFormat("Multiple Note On Msgs. Ignored ID: {0}", channelMsg.Data1); } } } // When encounter NoteOff message, Find corresponding NoteOn message in hash table // and calculate duration. Update the duration of that note. else if (channelMsg.Command == ChannelCommand.NoteOff) { NoteWithDuration noteOff; if (noteToTicksTable.TryGetValue(channelMsg.Data1, out noteOff)) { //UnityEngine.Debug.LogFormat("OFF, {0}", channelMsg.Data1); noteOff.Duration = enumerator.Current.AbsoluteTicks - noteOff.AbsoluteTicks; // TODO: Test if this works noteToTicksTable.Remove(channelMsg.Data1); } } } } // Find first tick of NoteOn message among the tracks for (int i = 0; i < notesList.Count; i++) { firstTick = (firstTick == -1 || notesList[i].FirstTick < firstTick) ? notesList[i].FirstTick : firstTick; } // Find last tick of NoteOn message among the tracks for (int i = 0; i < Sequence.Count; i++) { UnityEngine.Debug.LogFormat("Sequence track length: {0}", Sequence[i].Length); lastTick = (lastTick == -1 || Sequence[i].Length > lastTick) ? Sequence[i].Length : lastTick; } }