Skip to content

Commit

Permalink
Format changes, after discussions with a few people
Browse files Browse the repository at this point in the history
  • Loading branch information
mdsitton committed Apr 14, 2022
1 parent ed6d4f3 commit 6c19e93
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 29 deletions.
65 changes: 40 additions & 25 deletions BChart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,58 +21,71 @@ public static class BChartWriter
public static void WriteHeader(FileStream fs, uint instrumentCount, uint resolution)
{
// header
fs.WriteUInt16LE(0xBCAF);
const int headerLength = 6;
fs.WriteUInt32LE(0x46484342); // BCHF
fs.WriteUInt32LE(headerLength);
fs.WriteUInt16LE(1); // version 1
fs.WriteUInt16LE((ushort)resolution);
fs.WriteUInt16LE((ushort)instrumentCount);
}

public static void WriteTextEvent(FileStream fs, ChartEvent ev)
public static byte[] GetStringAsBytes(ReadOnlySpan<char> chars, out Span<byte> spanOut)
{
ReadOnlySpan<char> textSpan = ev.eventName;

int estCharCount = Encoding.UTF8.GetByteCount(textSpan);
int estCharCount = Encoding.UTF8.GetByteCount(chars);
byte[] bytes = ArrayPool<byte>.Shared.Rent(estCharCount);
Span<byte> outSpan = bytes;
Encoding.UTF8.GetBytes(textSpan, outSpan);
Encoding.UTF8.GetBytes(chars, outSpan);
spanOut = outSpan;
return bytes;
}

public static void WriteTextEvent(FileStream fs, ChartEvent ev)
{

byte[] bytes = GetStringAsBytes(ev.eventName, out var outSpan);

// limit string size to ushort max value
if (outSpan.Length > ushort.MaxValue)
{
outSpan = outSpan.Slice(0, ushort.MaxValue);
}
fs.WriteUInt32LE(ev.tick);
fs.WriteByte(EVENT_TEXT);
fs.WriteUInt32LE((uint)outSpan.Length);
fs.WriteUInt16LE((ushort)outSpan.Length);
fs.Write(outSpan);

ArrayPool<byte>.Shared.Return(bytes);
}

public static void WriteTextEvent(FileStream fs, Event ev)
{
ReadOnlySpan<char> textSpan = ev.title;

int estCharCount = Encoding.UTF8.GetByteCount(textSpan);
byte[] bytes = ArrayPool<byte>.Shared.Rent(estCharCount);
Span<byte> outSpan = bytes;
Encoding.UTF8.GetBytes(textSpan, outSpan);
byte[] bytes = GetStringAsBytes(ev.title, out var outSpan);

// limit string size to ushort max value
if (outSpan.Length > ushort.MaxValue)
{
outSpan = outSpan.Slice(0, ushort.MaxValue);
}
fs.WriteUInt32LE(ev.tick);
fs.WriteByte(EVENT_TEXT);
fs.WriteUInt32LE((uint)outSpan.Length);
fs.WriteUInt16LE((ushort)outSpan.Length);
fs.Write(outSpan);

ArrayPool<byte>.Shared.Return(bytes);
}

public static void WriteSection(FileStream fs, Section section)
{
ReadOnlySpan<char> textSpan = section.title;

int estCharCount = Encoding.UTF8.GetByteCount(textSpan);
byte[] bytes = ArrayPool<byte>.Shared.Rent(estCharCount);
Span<byte> outSpan = bytes;
Encoding.UTF8.GetBytes(textSpan, outSpan);
byte[] bytes = GetStringAsBytes(section.title, out var outSpan);

// limit string size to ushort max value
if (outSpan.Length > ushort.MaxValue)
{
outSpan = outSpan.Slice(0, ushort.MaxValue);
}
fs.WriteUInt32LE(section.tick);
fs.WriteByte(EVENT_SECTION);
fs.WriteUInt32LE((uint)outSpan.Length);
fs.WriteUInt16LE((ushort)outSpan.Length);
fs.Write(outSpan);

ArrayPool<byte>.Shared.Return(bytes);
Expand Down Expand Up @@ -100,7 +113,7 @@ public static void WritePhrase(FileStream fs, byte phraseType, uint tick, uint t
{
fs.WriteUInt32LE(tick);
fs.WriteByte(EVENT_PHRASE);
fs.WriteUInt32LE(5);
fs.WriteUInt16LE(5);
fs.WriteByte(phraseType);
fs.WriteUInt32LE(tickLength);
}
Expand All @@ -123,9 +136,11 @@ public static void WriteNote(FileStream fs, Note note)
modifierLength++;
}

ushort byteLength = (ushort)(eventLength + modifierLength);

fs.WriteUInt32LE(note.tick);
fs.WriteByte(EVENT_NOTE);
fs.WriteUInt32LE(eventLength + modifierLength);
fs.WriteUInt16LE(byteLength);
fs.WriteUInt16LE((ushort)note.rawNote);
fs.WriteUInt32LE(note.length);
fs.WriteByte(modifierLength);
Expand Down Expand Up @@ -240,7 +255,7 @@ public static void WriteTimeSignature(FileStream fs, TimeSignature ts)
{
fs.WriteUInt32LE(ts.tick);
fs.WriteByte(EVENT_TIME_SIG);
fs.WriteUInt32LE(2);
fs.WriteUInt16LE(2);
fs.WriteByte((byte)ts.numerator);
fs.WriteByte((byte)ts.denominator);
}
Expand All @@ -251,7 +266,7 @@ public static void WriteTempo(FileStream fs, BPM bpm)
uint microSecondsPerQuarter = (uint)(microsecondsPerMinute * 1000 / bpm.value);
fs.WriteUInt32LE(bpm.tick);
fs.WriteByte(EVENT_TEMPO);
fs.WriteUInt32LE(4);
fs.WriteUInt16LE(4);
fs.WriteUInt32LE(microSecondsPerQuarter);
}

Expand Down
14 changes: 10 additions & 4 deletions chartFormat.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
bchart format:

event format:
[uint32 tickPos] [uint8 eventType] [uint32 eventByteLength] [eventData]
[uint32 tickPos] [uint8 eventType] [uint16 eventByteLength] [eventData]
event types:
[Tempo 0x01]
[0x01] [length 4] [uint32 tempo]
Expand All @@ -14,9 +14,10 @@ bchart format:
[Phrase 0x5]
[0x4] [length 2] [byte phraseType] [byte phraseType] [uint32 tickLength]
[Note 0x06]
[0x5] [7+noteModifiersLength] [uint16 noteNumber] [uint32 tickLength] [byte noteModifiersLength] [byte noteModifier1] [byte noteModifier2] [byte noteModifierX]
[0x5] [7+noteModifiersLength] [byte noteNumber] [uint32 tickLength] [byte noteModifiersLength] [byte noteModifier1] [byte noteModifier2] [byte noteModifierX]
header:
uint16 - 0xBCAF
uint32 - 0x46484342 - BCHF 0x42 0x43 0x48 0x46
uint32 - headerLength
uint16 - Version number
uint16 - Resolution
uint16 - instrumentCount
Expand All @@ -36,5 +37,10 @@ bchart format:

InstrumentDiffEvents:
difficultyID

[uint32 tickPos] [uint32 eventByteLength] [event data]


Other considerations:
Animation data, venue, characters, camera
Modchart events
Instrument shared events track (could be useful for various text events, solos sp etc)

0 comments on commit 6c19e93

Please sign in to comment.