Files
tbd-station-14/Content.Client/Instruments/MidiParser/MidiStreamWrapper.cs
Simon f5fbef7ccc Add the instrument names to the MIDI channel selector (#38083)
* Add the instrument to the MIDI channel selector

* Reviews

Adds support for chained masters
Makes the channel UI update on its own when the midi changes (Works with bands too!)

* add to admin logs and limit track count

* Limit track names by length too

* remove left over comment

* Requested changes

* Reviews
2025-06-11 20:32:48 +02:00

104 lines
2.6 KiB
C#

using System.IO;
using System.Text;
namespace Content.Client.Instruments.MidiParser;
public sealed class MidiStreamWrapper
{
private readonly MemoryStream _stream;
private byte[] _buffer;
public long StreamPosition => _stream.Position;
public MidiStreamWrapper(byte[] data)
{
_stream = new MemoryStream(data, writable: false);
_buffer = new byte[4];
}
/// <summary>
/// Skips X number of bytes in the stream.
/// </summary>
/// <param name="count">The number of bytes to skip. If 0, no operations on the stream are performed.</param>
public void Skip(int count)
{
if (count == 0)
return;
_stream.Seek(count, SeekOrigin.Current);
}
public byte ReadByte()
{
var b = _stream.ReadByte();
if (b == -1)
throw new Exception("Unexpected end of stream");
return (byte)b;
}
/// <summary>
/// Reads N bytes using the buffer.
/// </summary>
public byte[] ReadBytes(int count)
{
if (_buffer.Length < count)
{
Array.Resize(ref _buffer, count);
}
var read = _stream.Read(_buffer, 0, count);
if (read != count)
throw new Exception("Unexpected end of stream");
return _buffer;
}
/// <summary>
/// Reads a 4 byte big-endian uint.
/// </summary>
public uint ReadUInt32()
{
var bytes = ReadBytes(4);
return (uint)((bytes[0] << 24) |
(bytes[1] << 16) |
(bytes[2] << 8) |
(bytes[3]));
}
/// <summary>
/// Reads a 2 byte big-endian ushort.
/// </summary>
public ushort ReadUInt16()
{
var bytes = ReadBytes(2);
return (ushort)((bytes[0] << 8) | bytes[1]);
}
public string ReadString(int count)
{
var bytes = ReadBytes(count);
return Encoding.UTF8.GetString(bytes, 0, count);
}
public uint ReadVariableLengthQuantity()
{
uint value = 0;
// variable-length-quantities encode ints using 7 bits per byte
// the highest bit (7) is used for a continuation flag. We read until the high bit is 0
while (true)
{
var b = ReadByte();
value = (value << 7) | (uint)(b & 0x7f); // Shift current value and add 7 bits
// value << 7, make room for the next 7 bits
// b & 0x7F mask out the high bit to just get the 7 bit payload
if ((b & 0x80) == 0)
break; // This was the last bit.
}
return value;
}
}