public void Save(Stream stream) { EndianReader writer = new EndianReader(stream, Endianness.BigEndian); writer.Write(0x4D546864); writer.Write((uint)6); writer.Write((ushort)Type); writer.Write((ushort)Tracks.Count); if (Division is TicksPerBeatDivision) { writer.Write((Division as TicksPerBeatDivision).TicksPerBeat); } else { writer.Write((ushort)(0x8000 | ((Division as FramesPerSecondDivision).FramesPerSecond << 8) | (Division as FramesPerSecondDivision).TicksPerFrame)); } foreach (Track track in Tracks) { writer.Write(0x4D54726B); MemoryStream memory = new MemoryStream(); EndianReader mwriter = new EndianReader(memory, Endianness.BigEndian); foreach (Event e in track.Events) { Mid.WriteVariable(memory, (int)e.DeltaTime); if (e is MetaEvent) { mwriter.Write((byte)0xFF); mwriter.Write(e.Type); Mid.WriteVariable(memory, (int)(e as MetaEvent).Data.Length); mwriter.Write((e as MetaEvent).Data); } else { ChannelEvent c = e as ChannelEvent; mwriter.Write((byte)((c.Type << 4) | c.Channel)); mwriter.Write(c.Parameter1); if (e.Type != 0xC && e.Type != 0xD) { mwriter.Write(c.Parameter2); } } } writer.Write((uint)memory.Length); memory.Position = 0; Util.StreamCopy(stream, memory); } }
public Mid ToMid() { Mid mid = new Mid(); mid.Type = Mid.MidiType.Uniform; mid.Division = Division; Mid.Track beat = new Mid.Track(); beat.Events.Add(new Mid.MetaEvent() { DeltaTime = 0, Type = 0x03, Data = (Name == null || Name.Length == 0) ? Util.Encoding.GetBytes("rawksd") : Util.Encoding.GetBytes(Name) }); List <Event> events = new List <Event>(); events.AddRange(BPM.ToArray()); events.AddRange(Signature.ToArray()); events.Sort(new EventComparer()); ulong delta = 0; foreach (Event e in events) { if (e is TimeSignatureEvent) { TimeSignatureEvent sig = e as TimeSignatureEvent; beat.Events.Add(new Mid.MetaEvent() { DeltaTime = (uint)(sig.Time - delta), Type = 0x58, Data = new byte[] { sig.Numerator, sig.Denominator, sig.Metronome, sig.NumberOf32ndNotes } }); } else if (e is TempoEvent) { TempoEvent bpm = e as TempoEvent; byte[] mpqn = new byte[3]; Array.Copy(BigEndianConverter.GetBytes(bpm.MicrosecondsPerBeat), 1, mpqn, 0, 3); beat.Events.Add(new Mid.MetaEvent() { DeltaTime = (uint)(bpm.Time - delta), Type = 0x51, Data = mpqn }); } delta = e.Time; } beat.Events.Add(new Mid.MetaEvent() { DeltaTime = 0, Type = 0x2F, Data = new byte[0] }); mid.Tracks.Add(beat); foreach (Track t in Tracks) { events.Clear(); t.Comments.ForEach(e => { if (e.Type == TextEvent.TextEventType.Unknown) { e.Type = TextEvent.TextEventType.Comment; } }); t.Lyrics.ForEach(e => { if (e.Type == TextEvent.TextEventType.Unknown) { e.Type = TextEvent.TextEventType.Lyric; } }); t.Markers.ForEach(e => { if (e.Type == TextEvent.TextEventType.Unknown) { e.Type = TextEvent.TextEventType.Marker; } }); events.AddRange(t.Notes.ToArray()); events.AddRange(t.Comments.ToArray()); events.AddRange(t.Markers.ToArray()); events.AddRange(t.Lyrics.ToArray()); events.Sort(new EventComparer()); delta = 0; Mid.Track track = new Mid.Track(); track.Events.Add(new Mid.MetaEvent() { DeltaTime = 0, Type = 0x03, Data = Util.Encoding.GetBytes(t.Name) }); List <NoteEvent> OpenNotes = new List <NoteEvent>(); foreach (Event e in events) { __fuck_labels_opennotesagain: foreach (NoteEvent n in OpenNotes) { if (n.Time + n.Duration <= e.Time) { track.Events.Add(new Mid.ChannelEvent() { DeltaTime = (uint)(n.Time + n.Duration - delta), Channel = n.Channel, Type = 0x8, Parameter1 = n.Note, Parameter2 = n.ReleaseVelocity }); delta = n.Time + n.Duration; OpenNotes.Remove(n); goto __fuck_labels_opennotesagain; // Yeah, too lazy to make a ToRemove list } } if (e is NoteEvent) { NoteEvent n = e as NoteEvent; NoteEvent overlap = OpenNotes.Find(n2 => n2.Note == n.Note); if (overlap != null) // Stretch the open note over the colliding note { overlap.Duration = Math.Max(overlap.Duration, n.Time + n.Duration - overlap.Time); OpenNotes.Sort(new NoteEventComparer()); continue; } else { OpenNotes.Insert(0, n); OpenNotes.Sort(new NoteEventComparer()); track.Events.Add(new Mid.ChannelEvent() { DeltaTime = (uint)(n.Time - delta), Channel = n.Channel, Type = 0x9, Parameter1 = n.Note, Parameter2 = n.Velocity }); } } else if (e is TextEvent) { TextEvent l = e as TextEvent; track.Events.Add(new Mid.MetaEvent() { DeltaTime = (uint)(l.Time - delta), Type = (byte)l.Type, Data = Util.Encoding.GetBytes(l.Text) }); } else if (e is TextEvent) { TextEvent c = e as TextEvent; track.Events.Add(new Mid.MetaEvent() { DeltaTime = (uint)(c.Time - delta), Type = 0x1, Data = Util.Encoding.GetBytes(c.Text) }); } delta = e.Time; } foreach (NoteEvent n in OpenNotes) { track.Events.Add(new Mid.ChannelEvent() { DeltaTime = (uint)(n.Time + n.Duration - delta), Channel = n.Channel, Type = 0x8, Parameter1 = n.Note, Parameter2 = n.ReleaseVelocity }); delta = n.Time + n.Duration; } track.Events.Add(new Mid.MetaEvent() { DeltaTime = 0, Type = 0x2F, Data = new byte[0] }); mid.Tracks.Add(track); } return(mid); }
public static Midi Create(Mid mid) { Midi midi = new Midi(); midi.Division = mid.Division as Mid.TicksPerBeatDivision; List <NoteEvent> OpenNotes = new List <NoteEvent>(); foreach (Mid.Track t in mid.Tracks) { Track track = new Track(); ulong time = 0; foreach (Mid.Event e in t.Events) { time += e.DeltaTime; if (e is Mid.MetaEvent) { Mid.MetaEvent meta = e as Mid.MetaEvent; if (meta.Type == 0x3) { track.Name = Util.Encoding.GetString(meta.Data); if (midi.Name == null) { midi.Name = track.Name; } } else if (meta.Type == 0x1) { track.Comments.Add(new TextEvent(time, Util.Encoding.GetString(meta.Data))); } else if (meta.Type == 0x5) { track.Lyrics.Add(new TextEvent(time, Util.Encoding.GetString(meta.Data))); } else if (meta.Type == 0x6) { track.Markers.Add(new TextEvent(time, Util.Encoding.GetString(meta.Data))); } else if (meta.Type == 0x51) { byte[] data = new byte[4]; meta.Data.CopyTo(data, 1); midi.BPM.Add(new TempoEvent(time, BigEndianConverter.ToUInt32(data))); } else if (meta.Type == 0x58) { midi.Signature.Add(new TimeSignatureEvent(time, meta.Data[0], meta.Data[1], meta.Data[2], meta.Data[3])); } else if (meta.Type == 0x2F) { } //else //throw new Exception("OHSHIT"); } else if (e is Mid.ChannelEvent) { Mid.ChannelEvent c = e as Mid.ChannelEvent; if (c.Type == 0x8 || (c.Type == 0x9 && c.Parameter2 == 0)) // Note off // ( A note on with velocity 0 acts as a note off ) { NoteEvent note = OpenNotes.Find(n => n.Note == c.Parameter1); if (note != null) { note.Duration = time - note.Time; note.ReleaseVelocity = c.Parameter2; OpenNotes.Remove(note); } } else if (c.Type == 0x9) // Note on { NoteEvent note = new NoteEvent(time, c.Channel, c.Parameter1, c.Parameter2, 0); OpenNotes.Add(note); track.Notes.Add(note); } else if (c.Type == 0xC) // Program Change { InstrumentEvent change = new InstrumentEvent(time, c.Channel, c.Parameter1, c.Parameter2); track.Instruments.Add(change); } else if (c.Type == 0xB) // Controller { switch (c.Parameter1) { case 0x00: // Bank Select BankEvent bank = new BankEvent(time, c.Channel, c.Parameter2); track.Banks.Add(bank); break; } } //else //throw new Exception("OHSHIT"); } } if (track.Notes.Count > 0 || track.Comments.Count > 0 || track.Lyrics.Count > 0) { midi.Tracks.Add(track); } } return(midi); }
public static Mid Create(Stream stream) { EndianReader reader = new EndianReader(stream, Endianness.BigEndian); if (reader.ReadUInt32() != 0x4D546864) { return(null); } if (reader.ReadUInt32() != 6) { return(null); } Mid mid = new Mid(); mid.Type = (MidiType)reader.ReadUInt16(); ushort tracks = reader.ReadUInt16(); ushort division = reader.ReadUInt16(); if ((division & 0x8000) == 0) { mid.Division = new TicksPerBeatDivision((ushort)(division & 0x7FFF)); } else { mid.Division = new FramesPerSecondDivision() { FramesPerSecond = (byte)((division & 0x7F00) >> 8), TicksPerFrame = (byte)(division & 0x00FF) } }; for (int i = 0; i < tracks; i++) { Track track = new Track(); if (reader.ReadUInt32() != 0x4D54726B) { return(null); } uint size = reader.ReadUInt32(); uint pos = (uint)stream.Position; byte oldb = 0; while (stream.Position - pos < size) { uint delta = (uint)Mid.ReadVariable(stream); byte b = reader.ReadByte(); if (b == 0xFF) // Meta Event { MetaEvent e = new MetaEvent(); e.DeltaTime = delta; e.Type = reader.ReadByte(); uint length = (uint)Mid.ReadVariable(stream); e.Data = reader.ReadBytes((int)length); track.Events.Add(e); //if (e.Type == 0x2F) // End Track meta event //break; } else if (b == 0xF0) { throw new NotImplementedException(); } else if (b == 0xF7) { throw new NotImplementedException(); } else // Channel Event { ChannelEvent e = new ChannelEvent(); e.DeltaTime = delta; if ((b & 0x80) == 0) { e.Parameter1 = b; b = oldb; } else { oldb = b; e.Parameter1 = (byte)reader.ReadByte(); } e.Type = (byte)(b >> 4); e.Channel = (byte)(b & 0x0F); if (e.Type != 0xC && e.Type != 0xD) { e.Parameter2 = (byte)reader.ReadByte(); } track.Events.Add(e); } } mid.Tracks.Add(track); } return(mid); }