public Player(Mixer mixer, Config config) { _mixer = mixer; _config = config; _masterSWD = new SWD(Path.Combine(config.BGMPath, "bgm.swd")); _time = new TimeBarrier(192); }
public Player(Mixer mixer, Config config) { this.mixer = mixer; this.config = config; masterSWD = new SWD(Path.Combine(config.BGMPath, "bgm.swd")); time = new TimeBarrier(192); }
public void LoadSong(long index) { if (_tracks != null) { for (int i = 0; i < _tracks.Length; i++) { _tracks[i].StopAllChannels(); } _tracks = null; } string bgm = _config.BGMFiles[index]; _localSWD = new SWD(Path.ChangeExtension(bgm, "swd")); _smdFile = File.ReadAllBytes(bgm); using (var reader = new EndianBinaryReader(new MemoryStream(_smdFile))) { SMD.Header header = reader.ReadObject <SMD.Header>(); SMD.ISongChunk songChunk; switch (header.Version) { case 0x402: { songChunk = reader.ReadObject <SMD.SongChunk_V402>(); break; } case 0x415: { songChunk = reader.ReadObject <SMD.SongChunk_V415>(); break; } default: throw new Exception(string.Format(Strings.ErrorDSEInvalidHeaderVersion, header.Version)); } _tracks = new Track[songChunk.NumTracks]; Events = new List <SongEvent> [songChunk.NumTracks]; for (byte trackIndex = 0; trackIndex < songChunk.NumTracks; trackIndex++) { Events[trackIndex] = new List <SongEvent>(); bool EventExists(long offset) { return(Events[trackIndex].Any(e => e.Offset == offset)); } long chunkStart = reader.BaseStream.Position; reader.BaseStream.Position += 0x14; // Skip header _tracks[trackIndex] = new Track(trackIndex, reader.BaseStream.Position); uint lastNoteDuration = 0, lastRest = 0; bool cont = true; while (cont) { long offset = reader.BaseStream.Position; void AddEvent(ICommand command) { Events[trackIndex].Add(new SongEvent(offset, command)); } byte cmd = reader.ReadByte(); if (cmd <= 0x7F) { byte arg = reader.ReadByte(); int numParams = (arg & 0xC0) >> 6; int oct = ((arg & 0x30) >> 4) - 2; int k = arg & 0xF; if (k < 12) { uint duration; if (numParams == 0) { duration = lastNoteDuration; } else // Big Endian reading of 8, 16, or 24 bits { duration = 0; for (int b = 0; b < numParams; b++) { duration = (duration << 8) | reader.ReadByte(); } lastNoteDuration = duration; } if (!EventExists(offset)) { AddEvent(new NoteCommand { Key = (byte)k, OctaveChange = (sbyte)oct, Velocity = cmd, Duration = duration }); } } else { throw new Exception(string.Format(Strings.ErrorDSEInvalidKey, trackIndex, offset, k)); } } else if (cmd >= 0x80 && cmd <= 0x8F) { lastRest = Utils.FixedRests[cmd - 0x80]; if (!EventExists(offset)) { AddEvent(new RestCommand { Rest = lastRest }); } } else // 0x90-0xFF { // TODO: 0x95 - a rest that may or may not repeat depending on some condition within channels // TODO: 0x9E - may or may not jump somewhere else depending on an unknown structure switch (cmd) { case 0x90: { if (!EventExists(offset)) { AddEvent(new RestCommand { Rest = lastRest }); } break; } case 0x91: { lastRest = (uint)(lastRest + reader.ReadSByte()); if (!EventExists(offset)) { AddEvent(new RestCommand { Rest = lastRest }); } break; } case 0x92: { lastRest = reader.ReadByte(); if (!EventExists(offset)) { AddEvent(new RestCommand { Rest = lastRest }); } break; } case 0x93: { lastRest = reader.ReadUInt16(); if (!EventExists(offset)) { AddEvent(new RestCommand { Rest = lastRest }); } break; } case 0x94: { lastRest = (uint)(reader.ReadByte() | (reader.ReadByte() << 8) | (reader.ReadByte() << 16)); if (!EventExists(offset)) { AddEvent(new RestCommand { Rest = lastRest }); } break; } case 0x96: case 0x97: case 0x9A: case 0x9B: case 0x9F: case 0xA2: case 0xA3: case 0xA6: case 0xA7: case 0xAD: case 0xAE: case 0xB7: case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBD: case 0xC1: case 0xC2: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD9: case 0xDA: case 0xDE: case 0xE6: case 0xEB: case 0xEE: case 0xF4: case 0xF5: case 0xF7: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: { if (!EventExists(offset)) { AddEvent(new InvalidCommand { Command = cmd }); } break; } case 0x98: { if (!EventExists(offset)) { AddEvent(new FinishCommand()); } cont = false; break; } case 0x99: { if (!EventExists(offset)) { AddEvent(new LoopStartCommand { Offset = reader.BaseStream.Position }); } break; } case 0xA0: { byte octave = reader.ReadByte(); if (!EventExists(offset)) { AddEvent(new OctaveSetCommand { Octave = octave }); } break; } case 0xA1: { sbyte change = reader.ReadSByte(); if (!EventExists(offset)) { AddEvent(new OctaveAddCommand { OctaveChange = change }); } break; } case 0xA4: case 0xA5: // The code for these two is identical { byte tempoArg = reader.ReadByte(); if (!EventExists(offset)) { AddEvent(new TempoCommand { Command = cmd, Tempo = tempoArg }); } break; } case 0xAB: { byte[] bytes = reader.ReadBytes(1); if (!EventExists(offset)) { AddEvent(new SkipBytesCommand { Command = cmd, SkippedBytes = bytes }); } break; } case 0xAC: { byte voice = reader.ReadByte(); if (!EventExists(offset)) { AddEvent(new VoiceCommand { Voice = voice }); } break; } case 0xCB: case 0xF8: { byte[] bytes = reader.ReadBytes(2); if (!EventExists(offset)) { AddEvent(new SkipBytesCommand { Command = cmd, SkippedBytes = bytes }); } break; } case 0xD7: { ushort bend = reader.ReadUInt16(); if (!EventExists(offset)) { AddEvent(new PitchBendCommand { Bend = bend }); } break; } case 0xE0: { byte volume = reader.ReadByte(); if (!EventExists(offset)) { AddEvent(new VolumeCommand { Volume = volume }); } break; } case 0xE3: { byte expression = reader.ReadByte(); if (!EventExists(offset)) { AddEvent(new ExpressionCommand { Expression = expression }); } break; } case 0xE8: { byte panArg = reader.ReadByte(); if (!EventExists(offset)) { AddEvent(new PanpotCommand { Panpot = (sbyte)(panArg - 0x40) }); } break; } case 0x9D: case 0xB0: case 0xC0: { if (!EventExists(offset)) { AddEvent(new UnknownCommand { Command = cmd, Args = Array.Empty <byte>() }); } break; } case 0x9C: case 0xA9: case 0xAA: case 0xB1: case 0xB2: case 0xB3: case 0xB5: case 0xB6: case 0xBC: case 0xBE: case 0xBF: case 0xC3: case 0xD0: case 0xD1: case 0xD2: case 0xDB: case 0xDF: case 0xE1: case 0xE7: case 0xE9: case 0xEF: case 0xF6: { byte[] args = reader.ReadBytes(1); if (!EventExists(offset)) { AddEvent(new UnknownCommand { Command = cmd, Args = args }); } break; } case 0xA8: case 0xB4: case 0xD3: case 0xD5: case 0xD6: case 0xD8: case 0xF2: { byte[] args = reader.ReadBytes(2); if (!EventExists(offset)) { AddEvent(new UnknownCommand { Command = cmd, Args = args }); } break; } case 0xAF: case 0xD4: case 0xE2: case 0xEA: case 0xF3: { byte[] args = reader.ReadBytes(3); if (!EventExists(offset)) { AddEvent(new UnknownCommand { Command = cmd, Args = args }); } break; } case 0xDD: case 0xE5: case 0xED: case 0xF1: { byte[] args = reader.ReadBytes(4); if (!EventExists(offset)) { AddEvent(new UnknownCommand { Command = cmd, Args = args }); } break; } case 0xDC: case 0xE4: case 0xEC: case 0xF0: { byte[] args = reader.ReadBytes(5); if (!EventExists(offset)) { AddEvent(new UnknownCommand { Command = cmd, Args = args }); } break; } default: throw new Exception(string.Format(Strings.ErrorAlphaDreamDSEMP2KSDATInvalidCommand, trackIndex, offset, cmd)); } } } uint chunkLength = reader.ReadUInt32(chunkStart + 0xC); reader.BaseStream.Position += chunkLength; // Align 4 while (reader.BaseStream.Position % 4 != 0) { reader.BaseStream.Position++; } } SetTicks(); } }