Inheritance: CommandBase
Beispiel #1
0
        private static void ProcessCommands(Command[] commands, ref int currentCommandIndex, int depth)
        {
            if (depth > Constants.MaxProcessingStack)
            {
                throw new Exception(Resources.ProcessingStackOverflow);
            }

            if (depth < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(depth));
            }

            while (currentCommandIndex < commands.Length)
            {
                Command currentCommand = commands[currentCommandIndex];

                //Console.WriteLine(currentCommand.Name);

                if (currentCommand.Name.Equals(Constants.StartDefinition))
                {
                    currentCommandIndex++;
                    ParseDefinition(commands, ref currentCommandIndex, false);
                }
                else if (currentCommand.Name.Equals(Constants.RedefineDefinition))
                {
                    currentCommandIndex++;
                    ParseDefinition(commands, ref currentCommandIndex, true);
                }
                else if (currentCommand is IfCommand)
                {
                    IfCommand ifCommand = currentCommand as IfCommand;
                    FInteger  intValue  = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                    if (intValue.Value == Constants.True)
                    {
                        int ifCommandIndex = 0;
                        ProcessCommands(ifCommand.IfCommands.ToArray(), ref ifCommandIndex, depth + 1);
                    }
                    else
                    {
                        int elseCommandIndex = 0;
                        ProcessCommands(ifCommand.ElseCommands.ToArray(), ref elseCommandIndex, depth + 1);
                    }
                }
                else if (currentCommand.Name.Equals(Constants.Else))
                {
                }
                else if (currentCommand.Name.Equals(Constants.EndIf))
                {
                }
                else if (currentCommand is RepeatCommand)
                {
                    RepeatCommand repeatCommand = currentCommand as RepeatCommand;
                    FInteger      fInteger;
                    do
                    {
                        int repeatCommandIndex = 0;
                        ProcessCommands(repeatCommand.RepeatCommands.ToArray(), ref repeatCommandIndex, depth + 1);
                        fInteger = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                    } while (fInteger.Value == Constants.False);
                }
                else if (currentCommand.Name.Equals(Constants.Until))
                {
                }
                else if (currentCommand is LoopCommand)
                {
                    LoopCommand loopCommand = currentCommand as LoopCommand;

                    FInteger incrementor  = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                    FInteger currentValue = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                    FInteger targetValue  = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));

                    while (currentValue.Value != targetValue.Value)
                    {
                        Stack.Push(new Cell(targetValue.GetBytes()));
                        Stack.Push(new Cell(currentValue.GetBytes()));
                        Stack.Push(new Cell(incrementor.GetBytes()));
                        int loopCommandIndex = 0;
                        ProcessCommands(loopCommand.LoopCommands.ToArray(), ref loopCommandIndex, depth + 1);

                        incrementor         = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                        currentValue        = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                        targetValue         = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                        currentValue.Value += incrementor.Value;
                    }
                }
                else if (currentCommand.Name.Equals(Constants.EndLoop))
                {
                }
                else
                {
                    if ((_ioMode == IoModeEnum.Hex) && (IsHexInteger(currentCommand.Name)))
                    {
                        int intValue;

                        if (!int.TryParse(currentCommand.Name, System.Globalization.NumberStyles.HexNumber, null,
                                          out intValue))
                        {
                            throw new Exception(string.Format(Resources.InvalidHexInteger, currentCommand));
                        }

                        FInteger intConstant = new FInteger(intValue);
                        Stack.Push(new Cell(intConstant.GetBytes()));
                    }
                    else if ((_ioMode == IoModeEnum.Decimal) && (IsInteger(currentCommand.Name)))
                    {
                        int intValue;
                        if (!int.TryParse(currentCommand.Name, out intValue))
                        {
                            throw new Exception(string.Format(Resources.InvalidInteger, currentCommand));
                        }

                        FInteger intConstant = new FInteger(intValue);
                        Stack.Push(new Cell(intConstant.GetBytes()));
                    }
                    else
                    {
                        float floatValue;
                        if ((_ioMode == IoModeEnum.Fraction) && (IsFloat(currentCommand.Name)))
                        {
                            if (!float.TryParse(currentCommand.Name, out floatValue))
                            {
                                throw new Exception(string.Format(Resources.InvalidFloat, currentCommand));
                            }

                            FFloat intConstant = new FFloat(floatValue);
                            Stack.Push(new Cell(intConstant.GetBytes()));
                        }
                        else if ((_ioMode == IoModeEnum.Char) && (IsChar(currentCommand.Name)))
                        {
                            string subString = currentCommand.Name.Substring(Constants.StartChar.Length,
                                                                             currentCommand.Name.Length - Constants.EndChar.Length - 1);
                            char ch;
                            if (!char.TryParse(subString, out ch))
                            {
                                throw new Exception(string.Format(Resources.InvalidCharacter, subString));
                            }

                            FInteger intConstant = new FInteger(ch);
                            Stack.Push(new Cell(intConstant.GetBytes()));
                        }
                        else if (IsString(currentCommand.Name))
                        {
                            string subString = currentCommand.Name.Substring(Constants.StartString.Length,
                                                                             currentCommand.Name.Length - Constants.EndString.Length - 2);
                            Console.Write(subString);
                        }
                        else if (IsVariable(currentCommand.Name))
                        {
                            Stack.Push(new Cell(new FInteger(Objects[currentCommand.Name].Item2).GetBytes()));
                        }
                        else if (IsValue(currentCommand.Name))
                        {
                            byte[] bytes = new byte[Constants.CellSize];
                            Array.Copy(Memory, Objects[currentCommand.Name].Item2, bytes, 0, Constants.CellSize);
                            Stack.Push(new Cell(bytes));
                        }
                        else if (IsConstant(currentCommand.Name))
                        {
                            byte[] bytes = new byte[Constants.CellSize];
                            Array.Copy(Memory, Objects[currentCommand.Name].Item2, bytes, 0, Constants.CellSize);
                            Stack.Push(new Cell(bytes));
                        }
                        else if (IsDefinition(currentCommand.Name))
                        {
                            int definitionTokenIndex = 0;
                            ProcessCommands(Definitions[currentCommand.Name].ToArray(), ref definitionTokenIndex, depth + 1);
                        }
                        else if (currentCommand.Name.Equals(Constants.ViewDefinitions))
                        {
                            Console.WriteLine();
                            foreach (string key in Definitions.Keys)
                            {
                                Console.Write(Resources.Executor_ProcessCommands__StartDefinition, Constants.StartDefinition);
                                Console.Write(string.Format(Resources.Executor_ProcessCommands__Key, key).PadRight(18, ' '));
                                foreach (Command command in Definitions[key])
                                {
                                    Console.Write(string.Format("{0} ", command.Name));
                                }

                                Console.WriteLine(string.Format("{0}", Constants.EndDefinition));
                            }
                        }
                        else if (currentCommand.Name.Equals(Constants.ViewObjects))
                        {
                            Console.WriteLine();
                            foreach (string key in Objects.Keys)
                            {
                                Console.Write(string.Format("{0}", key).PadRight(20, ' '));
                                Console.Write(string.Format("{0}\t", Objects[key].Item1));
                                Console.Write(string.Format("{0}\t", Objects[key].Item2));

                                byte[] bytes = FetchFromMemory(new FInteger(Objects[key].Item2));
                                Console.WriteLine(string.Format("{0}", GetOutputValue(bytes)));
                            }
                        }
                        else if (currentCommand.Name.Equals(Constants.Help))
                        {
                            Console.WriteLine();
                            foreach (string command in Constants.ValidCommands)
                            {
                                Console.WriteLine(command);
                            }
                        }
                        else if (currentCommand.Name.Equals(Constants.Variable))
                        {
                            if (currentCommandIndex >= commands.Length - 1)
                            {
                                throw new Exception(Resources.ExpectedAName);
                            }

                            currentCommandIndex++;
                            string variableName = commands[currentCommandIndex].Name;
                            if (IsAlreadyDefined(variableName))
                            {
                                throw new Exception(string.Format(Resources.AlreadyDefined, variableName));
                            }

                            AddObject(variableName, MemoryEntryEnum.Variable);
                        }
                        else if (currentCommand.Name.Equals(Constants.Value))
                        {
                            if (currentCommandIndex >= commands.Length - 1)
                            {
                                throw new Exception(Resources.ExpectedAName);
                            }

                            currentCommandIndex++;
                            string variableName = commands[currentCommandIndex].Name;
                            if (IsAlreadyDefined(variableName))
                            {
                                throw new Exception(string.Format(Resources.AlreadyDefined, variableName));
                            }

                            AddObject(variableName, MemoryEntryEnum.Value, Stack.Pop().Bytes);
                        }
                        else if (currentCommand.Name.Equals(Constants.Constant))
                        {
                            if (currentCommandIndex >= commands.Length - 1)
                            {
                                throw new Exception(Resources.ExpectedAName);
                            }

                            currentCommandIndex++;
                            string variableName = commands[currentCommandIndex].Name;
                            if (IsAlreadyDefined(variableName))
                            {
                                throw new Exception(string.Format(Resources.AlreadyDefined, variableName));
                            }

                            AddObject(variableName, MemoryEntryEnum.Constant, Stack.Pop().Bytes);
                        }
                        else if (currentCommand.Name.Equals(Constants.Store))
                        {
                            FInteger memoryLocation = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                            FInteger intValue       = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));

                            StoreToMemory(intValue, memoryLocation);
                        }
                        else if (currentCommand.Name.Equals(Constants.Fetch))
                        {
                            FInteger memoryLocation = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));

                            byte[] bytes = FetchFromMemory(memoryLocation);

                            FInteger intValue = new FInteger(BitConverter.ToInt32(bytes, 0));
                            Stack.Push(new Cell(intValue.GetBytes()));
                        }
                        else if (currentCommand.Name.Equals(Constants.To))
                        {
                            if (currentCommandIndex >= commands.Length - 1)
                            {
                                throw new Exception(Resources.ExpectedAName);
                            }

                            currentCommandIndex++;
                            string valueName = commands[currentCommandIndex].Name;
                            if (!IsValue(valueName))
                            {
                                throw new Exception(string.Format(Resources.NameIsNotAValue, valueName));
                            }

                            SetObject(Objects[valueName].Item2, Stack.Pop().Bytes);
                        }
                        else if (currentCommand.Name.Equals(Constants.Cell))
                        {
                            Stack.Push(new Cell(new FInteger(Constants.CellSize).GetBytes()));
                        }
                        else if (currentCommand.Name.Equals(Constants.Here))
                        {
                            Stack.Push(new Cell(new FInteger(_memoryPointer).GetBytes()));
                        }
                        else if (currentCommand.Name.Equals(Constants.Allot))
                        {
                            FInteger memoryAllocBytes = new FInteger(BitConverter.ToInt32(Stack.Pop().Bytes, 0));
                            if (_memoryPointer + memoryAllocBytes.Value < 0)
                            {
                                throw new Exception(Resources.MemoryUnderflow);
                            }
                            else if (_memoryPointer + memoryAllocBytes.Value > Constants.MemorySize)
                            {
                                throw new Exception(Resources.MemoryOverflow);
                            }

                            _memoryPointer += memoryAllocBytes.Value;
                        }
                        else if (currentCommand.Name.Equals(Constants.Decimal))
                        {
                            _ioMode = IoModeEnum.Decimal;
                        }
                        else if (currentCommand.Name.Equals(Constants.Hex))
                        {
                            _ioMode = IoModeEnum.Hex;
                        }
                        else if (currentCommand.Name.Equals(Constants.Fractional))
                        {
                            _ioMode = IoModeEnum.Fraction;
                        }
                        else if (currentCommand.Name.Equals(Constants.Char))
                        {
                            _ioMode = IoModeEnum.Char;
                        }
                        else if (currentCommand.Name.Equals(Constants.Period))
                        {
                            OutputValue(Stack.Pop().Bytes);
                        }
                        else if (currentCommand.Name.Equals(Constants.Dup))
                        {
                            Stack.Dup();
                        }
                        else if (currentCommand.Name.Equals(Constants.Swap))
                        {
                            Stack.Swap();
                        }
                        else if (currentCommand.Name.Equals(Constants.Drop))
                        {
                            Stack.Drop();
                        }
                        else if (currentCommand.Name.Equals(Constants.Rot))
                        {
                            Stack.Rot();
                        }
                        else if (currentCommand.Name.Equals(Constants.Over))
                        {
                            Stack.Over();
                        }
                        else if (currentCommand.Name.Equals(Constants.Tuck))
                        {
                            Stack.Tuck();
                        }
                        else if (currentCommand.Name.Equals(Constants.Roll))
                        {
                            Stack.Roll();
                        }
                        else if (currentCommand.Name.Equals(Constants.Pick))
                        {
                            Stack.Pick();
                        }
                        else if (currentCommand.Name.Equals(Constants.Cr))
                        {
                            Console.WriteLine();
                        }
                        else if (
                            currentCommand.Name.Equals(Constants.Add) ||
                            currentCommand.Name.Equals(Constants.Subtract) ||
                            currentCommand.Name.Equals(Constants.Multiply) ||
                            currentCommand.Name.Equals(Constants.Modulus) ||
                            currentCommand.Name.Equals(Constants.Divide) ||
                            currentCommand.Name.Equals(Constants.GreaterThan) ||
                            currentCommand.Name.Equals(Constants.LessThan) ||
                            currentCommand.Name.Equals(Constants.GreaterThanOrEqual) ||
                            currentCommand.Name.Equals(Constants.LessThanOrEqual) ||
                            currentCommand.Name.Equals(Constants.Equal) ||
                            currentCommand.Name.Equals(Constants.NotEqual) ||
                            currentCommand.Name.Equals(Constants.And) ||
                            currentCommand.Name.Equals(Constants.Or) ||
                            currentCommand.Name.Equals(Constants.Not)
                            )
                        {
                            if (_ioMode == IoModeEnum.Fraction)
                            {
                                Stack.FloatMaths(currentCommand.Name);
                            }
                            else
                            {
                                Stack.IntMaths(currentCommand.Name);
                            }
                        }
                        else
                        {
                            throw new Exception(string.Format(Resources.UnknownItem, currentCommand.Name));
                        }
                    }
                }

                // Increment to next token
                currentCommandIndex++;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Main Parser function. Takes string of tokens and parses into Command elements.
        /// Most Commands will just be plain strings, but some ('if', 'loop' etc. will be
        /// dedicated commands with properties specifying the sub-commands to be executed)
        /// </summary>
        /// <param name="tokens">Array of tokens to parse</param>
        /// <param name="tokenIndex">Initial token index</param>
        /// <param name="stopTokens">Array of stop-tokens. E.g. 'If' parsing should stop on 'else' or 'endif'</param>
        /// <returns>Array of Command objects</returns>
        public static Command[] Parse(string[] tokens, ref int tokenIndex, string[] stopTokens)
        {
            List <Command> parsedTokens = new List <Command>();

            while (tokenIndex < tokens.Length)
            {
                string token = tokens[tokenIndex];
                if (token.Equals(Constants.If))
                {
                    IfCommand ifCommand = new IfCommand();

                    tokenIndex++;
                    ifCommand.IfCommands.AddRange(Parse(tokens, ref tokenIndex,
                                                        new[] { Constants.Else, Constants.EndIf }));
                    // Only parse the following tokens in our 'if' statement if the next token after the 'then' phase is *not*
                    // 'endif'. This is to handle 'else-less' 'if's where we are only programmed to handle what happens when
                    // the 'if' evaluation is true, and to do nothing when the 'if' evaluation is false.
                    if (tokenIndex >= 1 && !tokens[tokenIndex - 1].Equals(Constants.EndIf))
                    {
                        ifCommand.ElseCommands.AddRange(Parse(tokens, ref tokenIndex, new[] { Constants.EndIf }));
                    }

                    parsedTokens.Add(ifCommand);
                }
                else if (token.Equals(Constants.Loop))
                {
                    LoopCommand loopCommand = new LoopCommand();

                    tokenIndex++;
                    loopCommand.LoopCommands.AddRange(Parse(tokens, ref tokenIndex, new[] { Constants.EndLoop }));

                    parsedTokens.Add(loopCommand);
                }
                else if (token.Equals(Constants.Repeat))
                {
                    RepeatCommand repeatCommand = new RepeatCommand();

                    tokenIndex++;
                    repeatCommand.RepeatCommands.AddRange(Parse(tokens, ref tokenIndex,
                                                                new[] { Constants.Until }));

                    parsedTokens.Add(repeatCommand);
                }
                else
                {
                    // For anything that's not an 'if', or loop, just add the string as a command.
                    // The executor can handle if it's not an actual command
                    parsedTokens.Add(new Command(token));

                    if ((stopTokens != null) && (stopTokens.Contains(token)))
                    {
                        tokenIndex++;
                        return(parsedTokens.ToArray());
                    }

                    tokenIndex++;
                }
            }

            if (stopTokens != null)
            {
                // If we get here then 'stopTokens' was set to something that should terminate a sequence of commands,
                // but wasn't found. E.G. An 'if' without an 'endif'.
                throw new Exception(string.Format(Resources.Expected_, string.Join("/", stopTokens)));
            }

            return(parsedTokens.ToArray());
        }
Beispiel #3
0
        protected void Load(byte[] binary, EndianBinaryReader reader, int headerOffset)
        {
            _binary = binary;
            Header  = reader.ReadObject <M4ASongHeader>(headerOffset);

            VoiceTable = VoiceTable.LoadTable <M4AVoiceTable>(Header.VoiceTable - ROM.Pak);

            Commands = new List <SongEvent> [Header.NumTracks];
            for (int i = 0; i < Header.NumTracks; i++)
            {
                Commands[i] = new List <SongEvent>();
            }

            if (Header.NumTracks > ROM.Instance.Game.Engine.TrackLimit)
            {
                throw new InvalidDataException($"Song has too many tracks ({Header.NumTracks}).");
            }

            for (int i = 0; i < NumTracks; i++)
            {
                reader.BaseStream.Position = Header.Tracks[i] - ROM.Pak;

                byte cmd = 0, runCmd = 0, prevNote = 0, prevVelocity = 0x7F;

                while (cmd != 0xB1 && cmd != 0xB6)
                {
                    int      off     = (int)reader.BaseStream.Position;
                    ICommand command = null;

                    cmd = reader.ReadByte();
                    if (cmd >= 0xBD) // Commands that work within running status
                    {
                        runCmd = cmd;
                    }

                    #region TIE & Notes

                    if (runCmd >= 0xCF && cmd < 0x80) // Within running status
                    {
                        var peek = reader.PeekBytes(2);
                        if (peek[0] >= 0x80)
                        {
                            command = AddNoteEvent(cmd, prevVelocity, 0, runCmd, out prevNote, out prevVelocity);
                        }
                        else if (peek[1] > 3 || peek[1] < 1)
                        {
                            command = AddNoteEvent(cmd, reader.ReadByte(), 0, runCmd, out prevNote, out prevVelocity);
                        }
                        else
                        {
                            command = AddNoteEvent(cmd, reader.ReadByte(), reader.ReadByte(), runCmd, out prevNote, out prevVelocity);
                        }
                    }
                    else if (cmd >= 0xCF)
                    {
                        var peek = reader.PeekBytes(3);
                        if (peek[0] >= 0x80)
                        {
                            command = AddNoteEvent(prevNote, prevVelocity, 0, runCmd, out prevNote, out prevVelocity);
                        }
                        else if (peek[1] >= 0x80)
                        {
                            command = AddNoteEvent(reader.ReadByte(), prevVelocity, 0, runCmd, out prevNote, out prevVelocity);
                        }
                        // TIE cannot have an added duration so it needs to stop here
                        else if (cmd == 0xCF || peek[2] > 3 || peek[2] < 1)
                        {
                            command = AddNoteEvent(reader.ReadByte(), reader.ReadByte(), 0, runCmd, out prevNote, out prevVelocity);
                        }
                        else
                        {
                            command = AddNoteEvent(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), runCmd, out prevNote, out prevVelocity);
                        }
                    }

                    #endregion

                    #region Rests

                    else if (cmd >= 0x80 && cmd <= 0xB0)
                    {
                        command = new RestCommand {
                            Rest = SongEvent.RestFromCMD(0x80, cmd)
                        }
                    }
                    ;

                    #endregion

                    #region Commands

                    else if (runCmd < 0xCF && cmd < 0x80) // Commands within running status
                    {
                        switch (runCmd)
                        {
                        case 0xBD: command = new VoiceCommand {
                                Voice = cmd
                        }; break;

                        case 0xBE: command = new VolumeCommand {
                                Volume = cmd
                        }; break;

                        case 0xBF: command = new PanpotCommand {
                                Panpot = (sbyte)(cmd - 0x40)
                        }; break;

                        case 0xC0: command = new BendCommand {
                                Bend = (sbyte)(cmd - 0x40)
                        }; break;

                        case 0xC1: command = new BendRangeCommand {
                                Range = cmd
                        }; break;

                        case 0xC2: command = new LFOSpeedCommand {
                                Speed = cmd
                        }; break;

                        case 0xC3: command = new LFODelayCommand {
                                Delay = cmd
                        }; break;

                        case 0xC4: command = new ModDepthCommand {
                                Depth = cmd
                        }; break;

                        case 0xC5: command = new ModTypeCommand {
                                Type = cmd
                        }; break;

                        case 0xC8: command = new TuneCommand {
                                Tune = (sbyte)(cmd - 0x40)
                        }; break;

                        case 0xCD: command = new LibraryCommand {
                                Command = cmd, Argument = reader.ReadByte()
                        }; break;

                        case 0xCE: command = new EndOfTieCommand {
                                Note = (sbyte)cmd
                        }; prevNote = cmd; break;
                        }
                    }
                    else if (cmd > 0xB0 && cmd < 0xCF)
                    {
                        switch (cmd)
                        {
                        case 0xB1:     // FINE & PREV
                        case 0xB6: command = new M4AFinishCommand {
                                Type = cmd
                        }; break;

                        case 0xB2: command = new GoToCommand {
                                Offset = reader.ReadInt32() - ROM.Pak
                        }; break;

                        case 0xB3: command = new CallCommand {
                                Offset = reader.ReadInt32() - ROM.Pak
                        }; break;

                        case 0xB4: command = new ReturnCommand(); break;

                        case 0xB5: command = new RepeatCommand {
                                Times = reader.ReadByte(), Offset = reader.ReadInt32() - ROM.Pak
                        }; break;

                        case 0xB9: command = new MemoryAccessCommand {
                                Arg1 = reader.ReadByte(), Arg2 = reader.ReadByte(), Arg3 = reader.ReadByte()
                        }; break;

                        case 0xBA: command = new PriorityCommand {
                                Priority = reader.ReadByte()
                        }; break;

                        case 0xBB: command = new TempoCommand {
                                Tempo = (short)(reader.ReadByte() * 2)
                        }; break;

                        case 0xBC: command = new KeyShiftCommand {
                                Shift = reader.ReadSByte()
                        }; break;

                        // Commands that work within running status:
                        case 0xBD: command = new VoiceCommand {
                                Voice = reader.ReadByte()
                        }; break;

                        case 0xBE: command = new VolumeCommand {
                                Volume = reader.ReadByte()
                        }; break;

                        case 0xBF: command = new PanpotCommand {
                                Panpot = (sbyte)(reader.ReadByte() - 0x40)
                        }; break;

                        case 0xC0: command = new BendCommand {
                                Bend = (sbyte)(reader.ReadByte() - 0x40)
                        }; break;

                        case 0xC1: command = new BendRangeCommand {
                                Range = reader.ReadByte()
                        }; break;

                        case 0xC2: command = new LFOSpeedCommand {
                                Speed = reader.ReadByte()
                        }; break;

                        case 0xC3: command = new LFODelayCommand {
                                Delay = reader.ReadByte()
                        }; break;

                        case 0xC4: command = new ModDepthCommand {
                                Depth = reader.ReadByte()
                        }; break;

                        case 0xC5: command = new ModTypeCommand {
                                Type = reader.ReadByte()
                        }; break;

                        case 0xC8: command = new TuneCommand {
                                Tune = (sbyte)(reader.ReadByte() - 0x40)
                        }; break;

                        case 0xCD: command = new LibraryCommand {
                                Command = reader.ReadByte(), Argument = reader.ReadByte()
                        }; break;

                        case 0xCE:     // EOT
                            sbyte note;

                            if (reader.PeekByte() < 0x80)
                            {
                                note     = reader.ReadSByte();
                                prevNote = (byte)note;
                            }
                            else
                            {
                                note = -1;
                            }

                            command = new EndOfTieCommand {
                                Note = note
                            };
                            break;

                        default: Console.WriteLine("Invalid command: 0x{0:X} = {1}", off, cmd); break;
                        }
                    }

                    #endregion

                    Commands[i].Add(new SongEvent(off, command));
                }
            }

            ICommand AddNoteEvent(byte note, byte velocity, byte addedDuration, byte runCmd, out byte prevNote, out byte prevVelocity)
            {
                return(new M4ANoteCommand
                {
                    Note = (sbyte)(prevNote = note),
                    Velocity = prevVelocity = velocity,
                    Duration = (short)(runCmd == 0xCF ? -1 : (SongEvent.RestFromCMD(0xCF, runCmd) + addedDuration))
                });
            }
        }
Beispiel #4
0
        protected void Load(byte[] binary, M4ASongHeader head)
        {
            _binary = binary;
            Header  = head;
            Array.Resize(ref Header.Tracks, Header.NumTracks); // Not really necessary yet
            Commands = new List <SongEvent> [Header.NumTracks];
            for (int i = 0; i < Header.NumTracks; i++)
            {
                Commands[i] = new List <SongEvent>();
            }

            VoiceTable = VoiceTable.LoadTable <M4AVoiceTable>(Header.VoiceTable);

            if (NumTracks == 0 || NumTracks > 16)
            {
                return;
            }

            var reader = new ROMReader();

            reader.InitReader(_binary);

            for (int i = 0; i < NumTracks; i++)
            {
                reader.SetOffset(Header.Tracks[i]);

                byte cmd = 0, runCmd = 0, prevNote = 0, prevVelocity = 127;

                while (cmd != 0xB1 && cmd != 0xB6)
                {
                    uint     off     = reader.Position;
                    ICommand command = null;

                    cmd = reader.ReadByte();
                    if (cmd >= 0xBD) // Commands that work within running status
                    {
                        runCmd = cmd;
                    }

                    #region TIE & Notes

                    if (runCmd >= 0xCF && cmd < 0x80) // Within running status
                    {
                        var  o     = reader.Position;
                        byte peek1 = reader.ReadByte(),
                             peek2 = reader.ReadByte();
                        reader.SetOffset(o);
                        if (peek1 >= 128)
                        {
                            command = AddNoteEvent(cmd, prevVelocity, 0, runCmd, out prevNote, out prevVelocity);
                        }
                        else if (peek2 > 3 || peek2 < 1)
                        {
                            command = AddNoteEvent(cmd, reader.ReadByte(), 0, runCmd, out prevNote, out prevVelocity);
                        }
                        else
                        {
                            command = AddNoteEvent(cmd, reader.ReadByte(), reader.ReadByte(), runCmd, out prevNote, out prevVelocity);
                        }
                    }
                    else if (cmd >= 0xCF)
                    {
                        var  o     = reader.Position;
                        byte peek1 = reader.ReadByte(),
                             peek2 = reader.ReadByte(),
                             peek3 = reader.ReadByte();
                        reader.SetOffset(o);
                        if (peek1 >= 128)
                        {
                            command = AddNoteEvent(prevNote, prevVelocity, 0, runCmd, out prevNote, out prevVelocity);
                        }
                        else if (peek2 >= 128)
                        {
                            command = AddNoteEvent(reader.ReadByte(), prevVelocity, 0, runCmd, out prevNote, out prevVelocity);
                        }
                        // TIE cannot have an added duration so it needs to stop here
                        else if (cmd == 0xCF || peek3 > 3 || peek3 < 1)
                        {
                            command = AddNoteEvent(reader.ReadByte(), reader.ReadByte(), 0, runCmd, out prevNote, out prevVelocity);
                        }
                        else
                        {
                            command = AddNoteEvent(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), runCmd, out prevNote, out prevVelocity);
                        }
                    }

                    #endregion

                    #region Rests

                    else if (cmd >= 0x80 && cmd <= 0xB0)
                    {
                        command = new RestCommand {
                            Rest = SongEvent.RestFromCMD(0x80, cmd)
                        }
                    }
                    ;

                    #endregion

                    #region Commands

                    else if (runCmd < 0xCF && cmd < 0x80) // Commands within running status
                    {
                        switch (runCmd)
                        {
                        case 0xBD: command = new VoiceCommand {
                                Voice = cmd
                        }; break;

                        case 0xBE: command = new VolumeCommand {
                                Volume = cmd
                        }; break;

                        case 0xBF: command = new PanpotCommand {
                                Panpot = (sbyte)(cmd - 0x40)
                        }; break;

                        case 0xC0: command = new BendCommand {
                                Bend = (sbyte)(cmd - 0x40)
                        }; break;

                        case 0xC1: command = new BendRangeCommand {
                                Range = cmd
                        }; break;

                        case 0xC2: command = new LFOSpeedCommand {
                                Speed = cmd
                        }; break;

                        case 0xC3: command = new LFODelayCommand {
                                Delay = cmd
                        }; break;

                        case 0xC4: command = new ModDepthCommand {
                                Depth = cmd
                        }; break;

                        case 0xC5: command = new ModTypeCommand {
                                Type = cmd
                        }; break;

                        case 0xC8: command = new TuneCommand {
                                Tune = (sbyte)(cmd - 0x40)
                        }; break;

                        case 0xCD: command = new LibraryCommand {
                                Command = cmd, Argument = reader.ReadByte()
                        }; break;

                        case 0xCE: command = new EndOfTieCommand {
                                Note = (sbyte)cmd
                        }; prevNote = cmd; break;
                        }
                    }
                    else if (cmd > 0xB0 && cmd < 0xCF)
                    {
                        switch (cmd)
                        {
                        case 0xB1:     // FINE & PREV
                        case 0xB6: command = new M4AFinishCommand {
                                Type = cmd
                        }; break;

                        case 0xB2: command = new GoToCommand {
                                Offset = reader.ReadPointer()
                        }; break;

                        case 0xB3: command = new CallCommand {
                                Offset = reader.ReadPointer()
                        }; break;

                        case 0xB4: command = new ReturnCommand(); break;

                        case 0xB5: command = new RepeatCommand {
                                Times = reader.ReadByte(), Offset = reader.ReadPointer()
                        }; break;

                        case 0xB9: command = new MemoryAccessCommand {
                                Arg1 = reader.ReadByte(), Arg2 = reader.ReadByte(), Arg3 = reader.ReadByte()
                        }; break;

                        case 0xBA: command = new PriorityCommand {
                                Priority = reader.ReadByte()
                        }; break;

                        case 0xBB: command = new TempoCommand {
                                Tempo = (ushort)(reader.ReadByte() * 2)
                        }; break;

                        case 0xBC: command = new KeyShiftCommand {
                                Shift = reader.ReadSByte()
                        }; break;

                        // Commands that work within running status:
                        case 0xBD: command = new VoiceCommand {
                                Voice = reader.ReadByte()
                        }; break;

                        case 0xBE: command = new VolumeCommand {
                                Volume = reader.ReadByte()
                        }; break;

                        case 0xBF: command = new PanpotCommand {
                                Panpot = (sbyte)(reader.ReadByte() - 0x40)
                        }; break;

                        case 0xC0: command = new BendCommand {
                                Bend = (sbyte)(reader.ReadByte() - 0x40)
                        }; break;

                        case 0xC1: command = new BendRangeCommand {
                                Range = reader.ReadByte()
                        }; break;

                        case 0xC2: command = new LFOSpeedCommand {
                                Speed = reader.ReadByte()
                        }; break;

                        case 0xC3: command = new LFODelayCommand {
                                Delay = reader.ReadByte()
                        }; break;

                        case 0xC4: command = new ModDepthCommand {
                                Depth = reader.ReadByte()
                        }; break;

                        case 0xC5: command = new ModTypeCommand {
                                Type = reader.ReadByte()
                        }; break;

                        case 0xC8: command = new TuneCommand {
                                Tune = (sbyte)(reader.ReadByte() - 0x40)
                        }; break;

                        case 0xCD: command = new LibraryCommand {
                                Command = reader.ReadByte(), Argument = reader.ReadByte()
                        }; break;

                        case 0xCE:     // EOT
                            sbyte note;

                            if (reader.PeekByte() < 128)
                            {
                                note     = reader.ReadSByte();
                                prevNote = (byte)note;
                            }
                            else
                            {
                                note = -1;
                            }

                            command = new EndOfTieCommand {
                                Note = note
                            };
                            break;

                        default: Console.WriteLine("Invalid command: 0x{0:X} = {1}", reader.Position, cmd); break;
                        }
                    }

                    #endregion

                    Commands[i].Add(new SongEvent(off, command));
                }
            }

            ICommand AddNoteEvent(byte note, byte velocity, byte addedDuration, byte runCmd, out byte prevNote, out byte prevVelocity)
            {
                return(new M4ANoteCommand
                {
                    Note = (sbyte)(prevNote = note),
                    Velocity = prevVelocity = velocity,
                    Duration = (short)(runCmd == 0xCF ? -1 : (SongEvent.RestFromCMD(0xCF, runCmd) + addedDuration))
                });
            }
        }