private static void TestRemoveAt() { Track a = new Track(); ChannelMessage message = new ChannelMessage(ChannelCommand.NoteOff, 0, 60, 0); a.Insert(0, message); a.Insert(10, message); a.Insert(20, message); a.Insert(30, message); a.Insert(40, message); int count = a.Count; a.RemoveAt(0); Debug.Assert(a.Count == count - 1); a.RemoveAt(a.Count - 2); Debug.Assert(a.Count == count - 2); Debug.Assert(a.GetMidiEvent(0).AbsoluteTicks == 10); Debug.Assert(a.GetMidiEvent(a.Count - 2).AbsoluteTicks == 30); a.RemoveAt(0); a.RemoveAt(0); a.RemoveAt(0); Debug.Assert(a.Count == 1); }
private static void TestMerge() { Track a = new Track(); Track b = new Track(); a.Merge(b); Debug.Assert(a.Count == 1); ChannelMessage message = new ChannelMessage(ChannelCommand.NoteOff, 0, 60, 0); b.Insert(0, message); b.Insert(10, message); b.Insert(20, message); b.Insert(30, message); b.Insert(40, message); a.Merge(b); Debug.Assert(a.Count == 1 + b.Count - 1); a.Clear(); Debug.Assert(a.Count == 1); a.Insert(0, message); a.Insert(10, message); a.Insert(20, message); a.Insert(30, message); a.Insert(40, message); int count = a.Count; a.Merge(b); Debug.Assert(a.Count == count + b.Count - 1); Debug.Assert(a.GetMidiEvent(0).DeltaTicks == 0); Debug.Assert(a.GetMidiEvent(1).DeltaTicks == 0); Debug.Assert(a.GetMidiEvent(2).DeltaTicks == 10); Debug.Assert(a.GetMidiEvent(3).DeltaTicks == 0); Debug.Assert(a.GetMidiEvent(4).DeltaTicks == 10); Debug.Assert(a.GetMidiEvent(5).DeltaTicks == 0); Debug.Assert(a.GetMidiEvent(6).DeltaTicks == 10); Debug.Assert(a.GetMidiEvent(7).DeltaTicks == 0); Debug.Assert(a.GetMidiEvent(8).DeltaTicks == 10); Debug.Assert(a.GetMidiEvent(9).DeltaTicks == 0); }
static void ReadMidiTrack(MidiData midiData, Sanford.Multimedia.Midi.Track midiTrack, int sequencerDivision) { Dictionary <int, float> noteTimes = new Dictionary <int, float>(); Dictionary <int, float> noteVelocities = new Dictionary <int, float>(); for (int i = 0; i < midiTrack.Count; ++i) { MidiEvent midiEvent = midiTrack.GetMidiEvent(i); if (midiEvent.MidiMessage.GetBytes().Length < 3) { continue; } byte midiType = (byte)(midiEvent.MidiMessage.GetBytes()[0] & 0xFF); byte note = (byte)(midiEvent.MidiMessage.GetBytes()[1] & 0xFF); byte velocity = (byte)(midiEvent.MidiMessage.GetBytes()[2] & 0xFF); float time = (4.0f * midiEvent.AbsoluteTicks) / sequencerDivision; if (midiType == (byte)ChannelCommand.NoteOff || (midiType == (byte)ChannelCommand.NoteOn) && velocity == 0) { if (noteTimes.ContainsKey(note)) { Note noteObject = new Note(); noteObject.note = note; noteObject.start = noteTimes[note]; noteObject.end = time; noteObject.velocity = noteVelocities[note]; midiData.notes.Add(noteObject); noteTimes.Remove(note); noteVelocities.Remove(note); } } else if (midiType == (byte)ChannelCommand.NoteOn) { noteTimes[note] = time; noteVelocities[note] = Mathf.Min(1.0f, velocity / 127.0f); } } }
public override void SaveAsMIDI(string fileName) { if (NumTracks == 0) { throw new InvalidDataException("Questa canzone non ha tracce."); } CalculateTicks(); var midi = new Sequence(96) { Format = 1 }; var metaTrack = new Sanford.Multimedia.Midi.Track(); midi.Add(metaTrack); for (int i = 0; i < NumTracks; i++) { var track = new Sanford.Multimedia.Midi.Track(); midi.Add(track); FreeNoteCommand freeNote = null; MidiEvent freeNoteOff = null; for (int j = 0; j < Commands[i].Count; j++) { var e = Commands[i][j]; // Extended note ended ended and wasn't renewed if (freeNoteOff != null && freeNoteOff.AbsoluteTicks < e.AbsoluteTicks * 2) { freeNote = null; freeNoteOff = null; } if (e.Command is VolumeCommand vol) { track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Volume, vol.Volume / 2)); } else if (e.Command is VoiceCommand voice) { // TODO: Fork and remove restriction track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.ProgramChange, i, voice.Voice & 0x7F)); } else if (e.Command is PanpotCommand pan) { track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Pan, pan.Panpot / 2 + 0x40)); } else if (e.Command is BendCommand bend) { track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.PitchWheel, i, 0, bend.Bend / 2 + 0x40)); } else if (e.Command is BendRangeCommand bendr) { track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.Controller, i, 20, bendr.Range / 2)); } else if (e.Command is MLSSNoteCommand note) { // Extended note is playing and it should be extended by this note if (freeNote != null && freeNote.Note - 0x80 == note.Note) { // Move the note off command track.Move(freeNoteOff, freeNoteOff.AbsoluteTicks + note.Duration * 2); } // Extended note is playing but this note is different OR there is no extended note playing // Either way we play a new note and forget that one else { track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.NoteOn, i, note.Note, 0x7F)); track.Insert(e.AbsoluteTicks * 2 + note.Duration * 2, new ChannelMessage(ChannelCommand.NoteOff, i, note.Note)); freeNote = null; freeNoteOff = null; } } else if (e.Command is FreeNoteCommand free) { // Extended note is playing and it should be extended if (freeNote != null && freeNote.Note == free.Note) { // Move the note off command track.Move(freeNoteOff, freeNoteOff.AbsoluteTicks + free.Duration * 2); } // Extended note is playing but this note is different OR there is no extended note playing // Either way we play a new note and forget that one else { track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.NoteOn, i, free.Note - 0x80, 0x7F)); track.Insert(e.AbsoluteTicks * 2 + free.Duration * 2, new ChannelMessage(ChannelCommand.NoteOff, i, free.Note - 0x80)); freeNote = free; freeNoteOff = track.GetMidiEvent(track.Count - 2); // -1 would be the end of track event } } else if (i == 0 && e.Command is TempoCommand tempo) { var change = new TempoChangeBuilder { Tempo = (60000000 / tempo.Tempo) }; change.Build(); metaTrack.Insert(e.AbsoluteTicks * 2, change.Result); } else if (i == 0 && e.Command is GoToCommand goTo) { int jumpCmd = Commands[i].FindIndex(c => c.GetOffset() == goTo.Offset); metaTrack.Insert(Commands[i][jumpCmd].AbsoluteTicks * 2, new MetaMessage(MetaType.Marker, new byte[] { (byte)'[' })); metaTrack.Insert(e.AbsoluteTicks * 2, new MetaMessage(MetaType.Marker, new byte[] { (byte)']' })); } else if (e.Command is FinishCommand fine) { // TODO: Fix ticks before end of track event // Library automatically is updating track.EndOfTrackOffset for us break; } } } midi.Save(fileName); }
/// <summary> /// 添加mid文件到dataGridView /// </summary> /// <param name="trakInfo"></param> /// <param name="gridView"></param> private void AddTrackInfo2GridView(Sanford.Multimedia.Midi.Track trakInfo, DataGridView gridView) { //DataGridViewTextBoxColumn boxColumn = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn ColumnEventIndex = new DataGridViewTextBoxColumn(); ColumnEventIndex.HeaderText = "Event-Num"; ColumnEventIndex.Name = "ColumnEventIndex"; ColumnEventIndex.ReadOnly = true; //ColumnEventIndex.Width = 200; DataGridViewTextBoxColumn ColumnAbsTicks = new DataGridViewTextBoxColumn(); ColumnAbsTicks.HeaderText = "Abs-Ticks"; ColumnAbsTicks.Name = "ColumnAbsTicks"; ColumnAbsTicks.ReadOnly = true; //ColumnAbsTicks.Width = 80; // // ColumnDeltaTicks // DataGridViewTextBoxColumn ColumnDeltaTicks = new DataGridViewTextBoxColumn(); ColumnDeltaTicks.HeaderText = "Dlt Ticks"; ColumnDeltaTicks.Name = "ColumnDeltaTicks"; ColumnDeltaTicks.ReadOnly = true; // // ColumnMsgStatus // DataGridViewTextBoxColumn ColumnMsgStatus = new DataGridViewTextBoxColumn(); ColumnMsgStatus.HeaderText = "MsgStatus"; ColumnMsgStatus.Name = "ColumnMsgStatus"; ColumnMsgStatus.ReadOnly = true; // // ColumnMsgType // DataGridViewTextBoxColumn ColumnMsgType = new DataGridViewTextBoxColumn(); ColumnMsgType.HeaderText = "MsgType"; ColumnMsgType.Name = "ColumnMsgType"; ColumnMsgType.ReadOnly = true; // // ColumnMsgSubType // DataGridViewTextBoxColumn ColumnMsgSubType = new DataGridViewTextBoxColumn(); ColumnMsgSubType.HeaderText = "SubType"; ColumnMsgSubType.Name = "ColumnMsgSubType"; ColumnMsgSubType.ReadOnly = true; // // ColumnMsgData1 // DataGridViewTextBoxColumn ColumnMsgData1 = new DataGridViewTextBoxColumn(); ColumnMsgData1.HeaderText = "MsgData1"; ColumnMsgData1.Name = "ColumnMsgData1"; ColumnMsgData1.ReadOnly = true; // // ColumnMsgData2 // DataGridViewTextBoxColumn ColumnMsgData2 = new DataGridViewTextBoxColumn(); ColumnMsgData2.HeaderText = "MsgData2"; ColumnMsgData2.Name = "ColumnMsgData2"; ColumnMsgData2.ReadOnly = true; // // ColumnMidiChannel // DataGridViewTextBoxColumn ColumnMidiChannel = new DataGridViewTextBoxColumn(); ColumnMidiChannel.HeaderText = "MidiChannel"; ColumnMidiChannel.Name = "ColumnMidiChannel"; ColumnMidiChannel.ReadOnly = true; // // ColumnBytes // DataGridViewTextBoxColumn ColumnBytes = new DataGridViewTextBoxColumn(); ColumnBytes.HeaderText = "Bytes"; ColumnBytes.Name = "ColumnBytes"; ColumnBytes.ReadOnly = true; gridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; gridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { ColumnEventIndex, ColumnAbsTicks, ColumnDeltaTicks, ColumnMsgStatus, ColumnMsgType, ColumnMsgSubType, ColumnMsgData1, ColumnMsgData2, ColumnMidiChannel, ColumnBytes }); for (int i = 0; i < trakInfo.Count; i++) { MidiEvent me = trakInfo.GetMidiEvent(i); //listViewTrackInfo.Items.Add(string.Format("音轨{0},EventNo = {1} Msg type = {2} , status = {3}", i, j, me.MidiMessage.MessageType, me.MidiMessage.Status)); ArrayList stuff = new ArrayList(); stuff.Add(i); stuff.Add(me.AbsoluteTicks); stuff.Add(me.DeltaTicks); stuff.Add(me.MidiMessage.Status); stuff.Add(me.MidiMessage.MessageType); switch (me.MidiMessage.MessageType) { case MessageType.Channel: ChannelMessage cm = (ChannelMessage)me.MidiMessage; stuff.Add(cm.Command); stuff.Add(cm.Data1); stuff.Add(cm.Data2); stuff.Add(cm.MidiChannel); break; case MessageType.SystemExclusive: SysExMessage sem = (SysExMessage)me.MidiMessage; stuff.Add(sem.SysExType); break; case MessageType.SystemCommon: SysCommonMessage scm = (SysCommonMessage)me.MidiMessage; stuff.Add(scm.SysCommonType); stuff.Add(scm.Data1); stuff.Add(scm.Data2); break; case MessageType.SystemRealtime: SysRealtimeMessage srm = (SysRealtimeMessage)me.MidiMessage; stuff.Add(srm.SysRealtimeType); break; case MessageType.Meta: MetaMessage mm = (MetaMessage)me.MidiMessage; stuff.Add(mm.MetaType); //if (mm.MetaType == MetaType.TrackName) //{ // stuff.Add(""); //data1 // stuff.Add(""); //data2 // stuff.Add("");//MidiChannel // byte[] bytesTrkName = mm.GetBytes(); // //UnicodeEncoding encoding = new UnicodeEncoding(); // //string trackName = encoding.GetString(mm.GetBytes()); // //stuff.Add(/*trackName*/mm.GetBytes()); //} break; } //object[] stuff = { i, j, me.MidiMessage.MessageType,me.AbsoluteTicks }; gridView.Rows.Add(stuff.ToArray()); } }