static public Chart Read(Stream source) { BinaryReader reader = new BinaryReader(source); Chart chart = new Chart(); if (reader.ReadInt32() != 0x00000008) { throw new Exception("Can't load this file: invalid signature."); } long granularity = reader.ReadInt32(); while (true) { Entry entry = new Entry(); long eventOffset = reader.ReadInt16(); if (eventOffset >= 0x7FFF) { break; } entry.LinearOffset = new Fraction(eventOffset * granularity, 1000000); entry.Value = new Fraction(0, 1); int eventType = reader.ReadByte(); int eventValue = reader.ReadByte(); int eventParameter; eventParameter = eventType >> 4; eventType &= 0xF; // unhandled parameter types: // 0x05: measure length // also does not interpret note count 100% (it's a carryover from older bm formats) switch (eventType) { case 0x00: if (eventOffset > 0) { entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = eventParameter; } break; case 0x01: if (eventOffset > 0) { entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = eventParameter; } break; case 0x02: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = eventParameter; entry.Value = new Fraction(eventValue, 1); break; case 0x03: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = eventParameter; entry.Value = new Fraction(eventValue, 1); break; case 0x04: entry.Type = EntryType.Tempo; entry.Value = new Fraction(eventValue + (eventParameter * 256), 1); break; case 0x06: entry.Type = EntryType.EndOfSong; entry.Player = eventParameter + 1; break; case 0x07: entry.Type = EntryType.Marker; entry.Player = 0; entry.Value = new Fraction(eventValue, 1); entry.Parameter = eventParameter; break; case 0x08: entry.Type = EntryType.Judgement; entry.Player = 0; entry.Value = new Fraction(eventValue, 1); entry.Parameter = eventParameter; break; case 0x0C: entry.Type = (eventParameter == 0 ? EntryType.Measure : EntryType.Invalid); entry.Player = eventParameter + 1; break; default: entry.Type = EntryType.Invalid; break; } if (entry.Type != EntryType.Invalid) { chart.Entries.Add(entry); } } chart.Entries.Sort(); // find the default bpm foreach (Entry entry in chart.Entries) { if (entry.Type == EntryType.Tempo) { chart.DefaultBPM = entry.Value; break; } } // fill in the metric offsets chart.CalculateMetricOffsets(); return(chart); }
static public Chart Read(Stream source) { BinaryReaderEx reader = new BinaryReaderEx(source); Chart result = new Chart(); result.TickRate = new Fraction(100, 5980); int[] lastSample = new int[16]; int eventParameter = 0; int eventValue = 0; int eventType = 0; int eventOffset = 0; bool notecountMode = true; bool defaultBPMSet = false; while (true) { eventOffset = reader.ReadUInt16(); eventType = reader.ReadByte(); eventParameter = (eventType >> 4); eventType &= 0xF; eventValue = reader.ReadByte(); // end of chart? if (eventOffset == 0x7FFF) { break; } // ignore events in note count mode if (notecountMode) { if (eventType != 0 || eventOffset > 0) { notecountMode = false; } } // process events if (!notecountMode) { Entry entry = new Entry(); entry.LinearOffset = new Fraction(eventOffset, 1); switch (eventType) { case 0x0: // marker switch (eventParameter) { case 0x0: entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = 0; entry.Value = new Fraction(lastSample[0x0], 1); break; case 0x1: entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = 1; entry.Value = new Fraction(lastSample[0x1], 1); break; case 0x2: entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = 2; entry.Value = new Fraction(lastSample[0x2], 1); break; case 0x3: entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = 3; entry.Value = new Fraction(lastSample[0x3], 1); break; case 0x4: entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = 4; entry.Value = new Fraction(lastSample[0x4], 1); break; case 0x5: entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = 5; entry.Value = new Fraction(lastSample[0x5], 1); break; case 0x6: entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = 6; entry.Value = new Fraction(lastSample[0x6], 1); break; case 0x7: entry.Type = EntryType.Marker; entry.Player = 1; entry.Column = 7; entry.Value = new Fraction(lastSample[0x7], 1); break; } break; case 0x1: // marker switch (eventParameter) { case 0x0: entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = 0; entry.Value = new Fraction(lastSample[0x8], 1); break; case 0x1: entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = 1; entry.Value = new Fraction(lastSample[0x9], 1); break; case 0x2: entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = 2; entry.Value = new Fraction(lastSample[0xA], 1); break; case 0x3: entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = 3; entry.Value = new Fraction(lastSample[0xB], 1); break; case 0x4: entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = 4; entry.Value = new Fraction(lastSample[0xC], 1); break; case 0x5: entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = 5; entry.Value = new Fraction(lastSample[0xD], 1); break; case 0x6: entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = 6; entry.Value = new Fraction(lastSample[0xE], 1); break; case 0x7: entry.Type = EntryType.Marker; entry.Player = 2; entry.Column = 7; entry.Value = new Fraction(lastSample[0xF], 1); break; } break; case 0x2: // sample switch (eventParameter) { case 0x0: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = 0; lastSample[0x0] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x1: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = 1; lastSample[0x1] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x2: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = 2; lastSample[0x2] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x3: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = 3; lastSample[0x3] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x4: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = 4; lastSample[0x4] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x5: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = 5; lastSample[0x5] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x6: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = 6; lastSample[0x6] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x7: entry.Type = EntryType.Sample; entry.Player = 1; entry.Column = 7; lastSample[0x7] = eventValue; entry.Value = new Fraction(eventValue, 1); break; } break; case 0x3: // sample switch (eventParameter) { case 0x0: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = 0; lastSample[0x8] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x1: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = 1; lastSample[0x9] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x2: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = 2; lastSample[0xA] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x3: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = 3; lastSample[0xB] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x4: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = 4; lastSample[0xC] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x5: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = 5; lastSample[0xD] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x6: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = 6; lastSample[0xE] = eventValue; entry.Value = new Fraction(eventValue, 1); break; case 0x7: entry.Type = EntryType.Sample; entry.Player = 2; entry.Column = 7; lastSample[0xF] = eventValue; entry.Value = new Fraction(eventValue, 1); break; } break; case 0x4: // tempo entry.Type = EntryType.Tempo; entry.Value = new Fraction((eventParameter * 256) + eventValue, 1); if (!defaultBPMSet) { defaultBPMSet = true; result.DefaultBPM = entry.Value; } break; case 0x6: // end of song entry.Type = EntryType.EndOfSong; break; case 0x7: // bgm entry.Type = EntryType.Marker; entry.Player = 0; entry.Value = new Fraction(eventValue, 1); break; case 0xC: // measure entry.Type = EntryType.Measure; entry.Player = entry.Parameter + 1; break; case 0xE: // judgement entry.Type = EntryType.Judgement; entry.Value = new Fraction(eventValue, 1); entry.Parameter = eventParameter; break; } if (entry.Type != EntryType.Invalid) { result.Entries.Add(entry); } } } if (result.Entries.Count > 0) { result.Entries.Sort(); result.CalculateMetricOffsets(); } else { result = null; } return(result); }
static public Chart Read(Stream source) { BinaryReaderEx reader = new BinaryReaderEx(source); Chart result = new Chart(); result.TickRate = new Fraction(1, 1000); Dictionary <int, int> lastSample = new Dictionary <int, int>(); int eventParameter = 0; int eventValue = 0; int eventType = 0; int eventOffset = 0; int currentOffset = 0; bool defaultBPMSet = false; // read chart header reader.ReadBytes(0x20); while (true) { currentOffset += (int)reader.ReadUInt16S(); eventOffset = currentOffset; eventType = reader.ReadByte(); int eventPlayer = reader.ReadByte(); eventParameter = reader.ReadByte(); eventValue = reader.ReadByte(); eventValue |= (eventParameter & 0xF0) << 4; // end of chart? if (eventType == 0xFF) { break; } Entry entry = new Entry(); entry.LinearOffset = new Fraction(eventOffset, 1); int eventColumn; switch (eventType) { case 0x0: // marker if (eventValue >= 0x00 && eventValue <= 0x08) { if (eventPlayer <= 1) { if (eventValue == 0x05) { eventValue = 0x07; } else if (eventValue == 0x06) { eventValue = 0x05; } else if (eventValue == 0x07) { eventValue = 0x06; } eventColumn = eventValue + (eventPlayer * 0x10); entry.Type = EntryType.Marker; entry.Column = eventValue; entry.Player = eventPlayer + 1; if (lastSample.ContainsKey(eventColumn)) { entry.Value = new Fraction(lastSample[eventColumn], 1); } else { entry.Value = new Fraction(0, 1); } } break; } else { break; } case 0x2: // sample if (eventParameter >= 0x00 && eventParameter <= 0x08) { if (eventPlayer <= 1) { if (eventParameter == 0x05) { eventParameter = 0x07; } else if (eventParameter == 0x06) { eventParameter = 0x05; } else if (eventParameter == 0x07) { eventParameter = 0x06; } if (eventValue > 0) { eventValue++; } eventColumn = eventParameter + (eventPlayer * 0x10); entry.Type = EntryType.Sample; entry.Player = eventPlayer + 1; entry.Column = eventParameter; entry.Value = new Fraction(eventValue, 1); lastSample[eventColumn] = eventValue; } break; } else { break; } case 0x4: // tempo entry.Type = EntryType.Tempo; entry.Value = new Fraction(eventValue, 1); if (!defaultBPMSet) { defaultBPMSet = true; result.DefaultBPM = entry.Value; } break; case 0x6: // end of song entry.Type = EntryType.EndOfSong; break; case 0x7: // bgm if (eventValue > 0) { eventValue++; } entry.Type = EntryType.Marker; entry.Player = 0; entry.Value = new Fraction(eventValue, 1); break; case 0x8: // judgement entry.Type = EntryType.Judgement; entry.Value = new Fraction(eventValue, 1); entry.Parameter = eventParameter; break; case 0xB: // unknown break; case 0xC: // measure entry.Type = EntryType.Measure; entry.Player = entry.Player + 1; break; case 0xD: // unknown break; case 0xE: // bgm track? entry.Type = EntryType.Marker; entry.Player = 0; entry.Value = new Fraction(1, 1); break; default: break; } if (entry.Type != EntryType.Invalid) { result.Entries.Add(entry); } } if (result.Entries.Count > 0) { result.Entries.Sort(); result.CalculateMetricOffsets(); } else { result = null; } return(result); }