Created
November 4, 2025 15:44
-
-
Save leppie/90d0bc2c4633d38936dcd498d500b38d to your computer and use it in GitHub Desktop.
Use in VSCode with Binary File Viewer extension (also C# stuff)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| registerFileType((fileExt, filePath, fileData) => { | |
| if (fileExt == 'ncs') { | |
| const headerArray = fileData.getBytesAt(0, 4); | |
| const header = String.fromCharCode(...headerArray) | |
| if (header === 'USER') { | |
| return true; | |
| } | |
| } | |
| return false; | |
| }); | |
| /* | |
| TODO: | |
| * Project FX | |
| * Sidechain | |
| * Default macros for presets | |
| * Automation expansion | |
| */ | |
| registerParser(() => { | |
| setDefaults({ | |
| "colors": { | |
| "collapse": "blue", | |
| "offset": "yellow", | |
| "size": "yellow", | |
| "name": "white", | |
| "value": "magenta", | |
| "description": "green", | |
| "row-header": "cyan", | |
| "row-odd": "lightgray", | |
| "row-even": "lightgray", | |
| }, | |
| "dark-colors": { | |
| "collapse": "blue", | |
| "offset": "red", | |
| "size": "green", | |
| "name": "magenta", | |
| "value": "black", | |
| "description": "magenta", | |
| "row-header": "yellow", | |
| "row-odd": "lightgray", | |
| "row-even": "lightgray", | |
| } | |
| }); | |
| addStandardHeader(); | |
| read(4); | |
| addRow('Header', getStringValue(), "Always USER"); | |
| read(4); | |
| addRow('Filesize', getDecimalValue(), "Always 160780"); | |
| read(4); | |
| addRow('Unknown1', getHex0xValue(), "Always 1? File version?"); | |
| read(4); | |
| addRow('RootNote', getDecimalValue(), "Weird behavior"); | |
| read(32); | |
| addRow('Name', getStringValue(), "Padded with spaces"); | |
| read(4); | |
| addRow('Unknown2', getHex0xValue(), "Always zeros"); | |
| read(1); | |
| addRow('Tempo', getDecimalValue()); | |
| read(1); | |
| addRow('Swing', getDecimalValue()); | |
| read(1); | |
| addRow('Unknown3b', getHex0xValue(), "Always 3?"); | |
| read(1); | |
| addRow('Unknown3c', getHex0xValue(), "Always zeros"); | |
| read(8); | |
| addRow("Unknown8a", getHex0xValue(), "Always zeros"); | |
| read(644); | |
| addRow('Scene Manager'); | |
| addDetails(() => { | |
| for (var s = 0; s < 16; s++) { | |
| read(40); | |
| addRow("Scene " + (s + 1)); | |
| addDetails(()=> { | |
| addPatternMaps(); | |
| read(1); | |
| addRow("Enabled", getDecimalValue()); | |
| read(1); | |
| addRow("Muted", getBitsValue()); | |
| read(6); | |
| addRow("??", getHex0xValue(), "Always zeros?"); | |
| }); | |
| } | |
| read(4); | |
| addRow("Settings", getHex0xValue()); | |
| addDetails(()=> { | |
| read(1); | |
| addRow("Start Scene", getDecimalValue()); | |
| read(1); | |
| addRow("End Scene", getDecimalValue()); | |
| read(2); | |
| addRow("??", getHex0xValue(), "Always zeros?"); | |
| }); | |
| }); | |
| read(32); | |
| addRow("Pattern Manager"); | |
| addDetails(()=> { | |
| addPatternMaps(); | |
| }); | |
| read(8 * 3240); | |
| addRow("Synth 1"); | |
| addDetails(()=> { | |
| for (var s = 0; s < 8; s++) { | |
| addPattern(s + 1); | |
| } | |
| }); | |
| read(8 * 3240); | |
| addRow("Synth 2"); | |
| addDetails(()=> { | |
| for (var s = 0; s < 8; s++) { | |
| addPattern(s + 1); | |
| } | |
| }); | |
| read(8); | |
| addRow("Synth 1 Settings", getHex0xValue(), "Contains mute data"); | |
| read(8); | |
| addRow("Synth 2 Settings", getHex0xValue(), "Contains mute data"); | |
| read(1704 * 8); | |
| addRow("Drum 1"); | |
| addDetails(()=> { | |
| for (var d = 0; d < 8; d++) { | |
| addDrumPattern(d); | |
| } | |
| }); | |
| read(1704 * 8); | |
| addRow("Drum 2"); | |
| addDetails(()=> { | |
| for (var d = 0; d < 8; d++) { | |
| addDrumPattern(d); | |
| } | |
| }); | |
| read(1704 * 8); | |
| addRow("Drum 3"); | |
| addDetails(()=> { | |
| for (var d = 0; d < 8; d++) { | |
| addDrumPattern(d); | |
| } | |
| }); | |
| read(1704 * 8); | |
| addRow("Drum 4"); | |
| addDetails(()=> { | |
| for (var d = 0; d < 8; d++) { | |
| addDrumPattern(d); | |
| } | |
| }); | |
| read(4); | |
| addRow("Drum Mute", getHex0xValue()); | |
| addDetails(()=>{ | |
| read(1); | |
| addRow("Drum 1", getDecimalValue()); | |
| read(1); | |
| addRow("Drum 2", getDecimalValue()); | |
| read(1); | |
| addRow("Drum 3", getDecimalValue()); | |
| read(1); | |
| addRow("Drum 4", getDecimalValue()); | |
| }); | |
| read(4); | |
| addRow("Default Samples"); | |
| addDetails(()=>{ | |
| read(1); | |
| addRow("Drum 1", getDecimalValue()); | |
| read(1); | |
| addRow("Drum 2", getDecimalValue()); | |
| read(1); | |
| addRow("Drum 3", getDecimalValue()); | |
| read(1); | |
| addRow("Drum 4", getDecimalValue()); | |
| }); | |
| read(8 * 3240); | |
| addRow("MIDI 1"); | |
| addDetails(()=> { | |
| for (var s = 0; s < 8; s++) { | |
| addPattern(s + 1); | |
| } | |
| }); | |
| read(8 * 3240); | |
| addRow("MIDI 2"); | |
| addDetails(()=> { | |
| for (var s = 0; s < 8; s++) { | |
| addPattern(s + 1); | |
| } | |
| }); | |
| read(8); | |
| addRow("MIDI 1 Settings", getHex0xValue(), "Contains mute data"); | |
| read(8); | |
| addRow("MIDI 2 Settings", getHex0xValue(), "Contains mute data"); | |
| read(1); | |
| addRow("Unknown6b", getDecimalValue(), "NOT always zero"); | |
| read(1); | |
| addRow("Scale", getDecimalValue()); | |
| read(6); | |
| addRow("Unknown6c", getHex0xValue()); | |
| read(340); | |
| addRow('Synth 1 Patch', getStringValue().substring(0, 16)); | |
| addDetails(() => { | |
| read(340); | |
| addMemDump(); | |
| }); | |
| read(340); | |
| addRow('Synth 2 Patch', getStringValue().substring(0, 16)); | |
| addDetails(() => { | |
| read(340); | |
| addMemDump(); | |
| }); | |
| read(44); | |
| addRow("Drum Control/Mixer"); | |
| addDetails(()=>{ | |
| for (var c = 0; c < 4; c++) { | |
| read(11); | |
| addRow("Drum " + c, getHex0xValue()); | |
| addDetails(()=>{ | |
| read(1); | |
| addRow("Sample", getDecimalValue()); | |
| read(1); | |
| addRow("Level", getDecimalValue()); | |
| read(1); | |
| addRow("Pan", getDecimalValue()); | |
| read(4); | |
| addRow("Macros", getHex0xValue()); | |
| addDetails(()=>{ | |
| read(1); | |
| addRow("M1", getDecimalValue()); | |
| read(1); | |
| addRow("M2", getDecimalValue()); | |
| read(1); | |
| addRow("M3", getDecimalValue()); | |
| read(1); | |
| addRow("M4", getDecimalValue()); | |
| }); | |
| read(4); | |
| addRow("??", getHex0xValue(),"Always zeros?"); | |
| }); | |
| } | |
| }); | |
| read(32); | |
| addRow("Unknown"); | |
| addDetails(()=>{ | |
| read(32); | |
| addMemDump(); | |
| }); | |
| read(20); | |
| addRow("Something"); | |
| addDetails(()=>{ | |
| for (var u = 0; u < 4; u++){ | |
| read(5); | |
| addRow("?? " + (u + 1), getHex0xValue()); | |
| } | |
| }); | |
| read(4); | |
| addRow("Synth/Audio Mixer Level"); | |
| addDetails(()=> { | |
| read(1); | |
| addRow("Synth 1", getDecimalValue()); | |
| read(1); | |
| addRow("Synth 2", getDecimalValue()); | |
| read(1); | |
| addRow("Audio 1", getDecimalValue()); | |
| read(1); | |
| addRow("Audio 2", getDecimalValue()); | |
| }); | |
| read(4); | |
| addRow("Synth/Audio Mixer Pan"); | |
| addDetails(()=> { | |
| read(1); | |
| addRow("Synth 1", getDecimalValue()); | |
| read(1); | |
| addRow("Synth 2", getDecimalValue()); | |
| read(1); | |
| addRow("Audio 1", getDecimalValue()); | |
| read(1); | |
| addRow("Audio 2", getDecimalValue()); | |
| }); | |
| read(1000); | |
| addRow('Trailer', "", "Zeros for me, but seems like a hash? See Hello Tracks."); | |
| addDetails(() => { | |
| read(1000); | |
| addMemDump(); | |
| }); | |
| read(0); | |
| addRow("EOF", endOfFile(), "End of file check"); | |
| }); | |
| function addAutomation(n) { | |
| read(32 * 6); | |
| addRow(n); | |
| addDetails(()=>{ | |
| setEndianness('big'); | |
| for (var s = 0; s < 32; s++) { | |
| read(6); | |
| addRow("Step " + (s + 1), getHexValue(), "(be)"); | |
| } | |
| setEndianness('little'); | |
| }); | |
| } | |
| function addPatternMaps() { | |
| addPatternMap("Synth 1"); | |
| addPatternMap("Synth 2"); | |
| addPatternMap("MIDI 1"); | |
| addPatternMap("MIDI 2"); | |
| addPatternMap("Drum 1"); | |
| addPatternMap("Drum 2"); | |
| addPatternMap("Drum 3"); | |
| addPatternMap("Drum 4"); | |
| } | |
| function addPatternMap(n) { | |
| read(4); | |
| addRow(n, getHex0xValue()); | |
| addDetails(()=> { | |
| read(1); | |
| addRow("Start", getDecimalValue()); | |
| read(1); | |
| addRow("End", getDecimalValue()); | |
| read(2); | |
| addRow("??", getHex0xValue(), "Always zeros?"); | |
| }); | |
| } | |
| function addDrumPattern(d) { | |
| read(1704); | |
| addRow("Pattern " + (d + 1)); | |
| addDetails(() => { | |
| setEndianness("big"); | |
| read(32); | |
| addRow("Velocity", getHexValue(), "(be)"); | |
| read(32); | |
| addRow("Probability", getHexValue(), "(be) 0 - 7 scale"); | |
| read(32); | |
| addRow("Sample", getHexValue(), "(be)"); | |
| read(32); | |
| addRow("Microsteps", getHexValue(), "(be)"); | |
| setEndianness("little"); | |
| read(1); | |
| addRow("End Step", getDecimalValue()); | |
| read(1); | |
| addRow("Start Step", getDecimalValue()); | |
| read(1); | |
| addRow("SyncRate", getDecimalValue()); | |
| read(1); | |
| addRow("Play order", getDecimalValue()); | |
| read(4); | |
| addRow("??", getHex0xValue(), "Always zeros?"); | |
| read(32); | |
| addRow("Trailer", getHex0xValue(), "Zeros for me, but seems like a hash? See Hello Tracks."); | |
| read(1536); | |
| addRow("Automation", "", "32 x 6 x (4 + 4)"); | |
| addDetails(()=>{ | |
| addAutomation("M1"); | |
| addAutomation("M2"); | |
| addAutomation("M3"); | |
| addAutomation("M4"); | |
| addAutomation("Level"); | |
| addAutomation("Pan"); | |
| addAutomation("Delay"); | |
| addAutomation("Reverb"); | |
| }); | |
| }); | |
| } | |
| function addPattern(s) { | |
| read(3240); | |
| addRow("Pattern " + s); | |
| addDetails(() => { | |
| for (var i = 0; i < 32; i++) { | |
| read(28); | |
| addRow("Step " + (i + 1), getHex0xValue()); | |
| addDetails(() => { | |
| read(4); | |
| addRow('Settings', getHex0xValue()); | |
| addDetails(() => { | |
| read(1); | |
| addRow("Voice Flags", getBitsValue()); | |
| read(1); | |
| addRow("Probability", getDecimalValue(), "0 - 7 scale"); | |
| read(2); | |
| addRow("??", getHex0xValue(), "Always zeros?"); | |
| }); | |
| for (var ms = 1; ms < 7; ms++) { | |
| read(4); | |
| addRow('Note ' + ms, getHex0xValue()); | |
| addDetails(() => { | |
| read(1); | |
| addRow("Note", getDecimalValue()); | |
| readBits(7); | |
| addRow("Gate", getDecimalValue()); | |
| readBits(1); | |
| addRow("Tie in", getDecimalValue()); | |
| read(1); | |
| addRow("Microstep", getDecimalValue()); | |
| read(1); | |
| addRow("Velocity", getDecimalValue()); | |
| }); | |
| } | |
| }); | |
| } | |
| read(8); | |
| addRow("Settings", getHex0xValue()); | |
| addDetails(()=>{ | |
| read(1); | |
| addRow("End Step", getDecimalValue()); | |
| read(1); | |
| addRow("Start Step", getDecimalValue()); | |
| read(1); | |
| addRow("SyncRate", getDecimalValue()); | |
| read(1); | |
| addRow("Play order", getDecimalValue()); | |
| read(4); | |
| addRow("??", getHex0xValue(), "Always zeros?"); | |
| }); | |
| read(32); | |
| addRow("Trailer", getHex0xValue(), "Zeros for me, but seems like a hash? See Hello Tracks."); | |
| read(2304); | |
| addRow('Automation', "", "32 x 6 x (8 + 4)"); | |
| addDetails(() => { | |
| addAutomation("M1"); | |
| addAutomation("M2"); | |
| addAutomation("M3"); | |
| addAutomation("M4"); | |
| addAutomation("M5"); | |
| addAutomation("M6"); | |
| addAutomation("M7"); | |
| addAutomation("M8"); | |
| addAutomation("Level"); | |
| addAutomation("Pan"); | |
| addAutomation("Delay"); | |
| addAutomation("Reverb"); | |
| }); | |
| }); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // this is incomplete | |
| using System.Collections; | |
| using System.Runtime.CompilerServices; | |
| using System.Runtime.InteropServices; | |
| using Melanchall.DryWetMidi.Composing; | |
| [InlineArray(6)] unsafe struct Buffer6<T> { private T _element0; } | |
| [InlineArray(8)] unsafe struct Buffer8<T> { private T _element0; } | |
| [InlineArray(16)] unsafe struct Buffer16<T> { private T _element0; } | |
| [InlineArray(32)] unsafe struct Buffer32<T> { private T _element0; } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] | |
| unsafe struct Project | |
| { | |
| public fixed byte Header[4]; | |
| public int Filesize; | |
| public int Unknown1; | |
| public int RootNote; | |
| public fixed byte Name[32]; | |
| public uint Unknown2; | |
| public byte Tempo; | |
| public byte Swing; | |
| public byte Unknown3b; | |
| public byte Unknown3c; | |
| public long Unknown8a; | |
| public Buffer16<Scene> Scenes; | |
| public byte Start, End; | |
| private ushort unknown5; | |
| public Buffer8<PatternMap> PatternMap; | |
| public Buffer8<Pattern> Synth1, Synth2; | |
| public ulong Synth1Settings, Synth2Settings; | |
| public Buffer8<DrumPattern> Drum1, Drum2, Drum3, Drum4; | |
| public uint DrumMute; | |
| public uint DefaultSamples; | |
| public Buffer8<Pattern> Midi1, Midi2; | |
| public ulong Midi1Settings, Midi2Settings; | |
| public ulong Settings; | |
| public Patch Synth1Patch, Synth2Patch; | |
| public Mixer Mixer; | |
| public fixed byte Trailer[1000]; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
| unsafe struct Scene | |
| { | |
| public PatternMap | |
| Synth1, | |
| Synth2, | |
| Midi1, | |
| Midi2, | |
| Drum1, | |
| Drum2, | |
| Drum3, | |
| Drum4; | |
| public byte Enabled; | |
| public byte Muted; | |
| private ushort unknown1; | |
| private uint Unknown2; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
| unsafe struct PatternMap | |
| { | |
| public byte Start, End; | |
| private ushort unknown; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
| unsafe struct Pattern | |
| { | |
| public Buffer32<Step> Steps; | |
| public ulong Settings; | |
| public Buffer32<byte> Trailer; | |
| public Automation Automation; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
| unsafe struct Step | |
| { | |
| public byte Flags; | |
| public byte Probability; | |
| ushort unknown; | |
| public Buffer6<Voice> Voices; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
| unsafe struct Voice | |
| { | |
| public byte Note; | |
| public byte GateAndTieIn; | |
| public byte Microstep; | |
| public byte Velocity; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
| unsafe struct Automation | |
| { | |
| public AutomationChannel | |
| M1, | |
| M2, | |
| M3, | |
| M4, | |
| M5, | |
| M6, | |
| M7, | |
| M8, | |
| Level, | |
| Pan, | |
| Delay, | |
| Reverb; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
| unsafe struct DrumPattern | |
| { | |
| public Buffer32<byte> Velocity; | |
| public Buffer32<byte> Probability; | |
| public Buffer32<byte> Sample; | |
| public Buffer32<byte> Microsteps; | |
| public byte EndStep, StartStep, SyncRate, PlayOrder; | |
| public uint Unknown; | |
| public Buffer32<byte> Trailer; | |
| public DrumAutomation Automation; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
| unsafe struct DrumAutomation | |
| { | |
| public AutomationChannel | |
| M1, | |
| M2, | |
| M3, | |
| M4, | |
| Level, | |
| Pan, | |
| Delay, | |
| Reverb; | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 340)] | |
| unsafe struct Patch | |
| { | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 104)] | |
| unsafe struct Mixer | |
| { | |
| } | |
| [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 192)] | |
| unsafe struct AutomationChannel | |
| { | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment