예제 #1
0
        public JaiEventType loadNextOp()
        {
            if (OpcodeAddressStack.Count == 16)
            {
                OpcodeAddressStack.Dequeue();
            }
            if (OpcodeHistory.Count == 16)
            {
                OpcodeHistory.Dequeue();
            }

            OpcodeAddressStack.Enqueue((int)Sequence.BaseStream.Position); // push address to FIFO stack.

            State.current_address = (int)Sequence.BaseStream.Position;
            byte current_opcode = Sequence.ReadByte(); // Reads the current byte in front of the cursor.

            last_opcode = current_opcode;
            OpcodeHistory.Enqueue(current_opcode); // push opcode to FIFO stack



            if (current_opcode < 0x80)
            {
                State.note = current_opcode;                     // The note on event is laid out like a piano with 127 (0x7F1) keys.
                // So this means that the first 0x80 bytes are just pressing the individual keys.
                State.voice = Sequence.ReadByte();               // The next byte tells the voice, 0-8
                State.vel   = Sequence.ReadByte();               // And finally, the next byte will tell the velocity
                return(JaiEventType.NOTE_ON);                    // Return the note on event.
            }
            else if (current_opcode == (byte)JaiSeqEvent.WAIT_8) // Contrast to above, the opcode between these two is WAIT_U8
            {
                State.delay += Sequence.ReadByte();              // Add u8 ticks to the delay.

                return(JaiEventType.DELAY);
            }
            else if (current_opcode < 0x88)   // We already check if it's 0x80, so anything between here will be 0x81 and 0x87
            {
                // Only the first 7 bits are going to determine which voice we're stopping.
                State.voice = (byte)(current_opcode & 0x7F);
                return(JaiEventType.NOTE_OFF);
            }
            else   // Finally, we can fall into our CASE statement.
            {
                switch (current_opcode)
                {
                /* Delays and waits */
                case (byte)JaiSeqEvent.WAIT_16:          // Wait (UInt16)
                    State.delay = Sequence.ReadUInt16(); // Add to the state delay

                    return(JaiEventType.DELAY);

                case (byte)JaiSeqEvent.WAIT_VAR:     // Wait (VLQ) see readVlq function.
                    State.delay += Helpers.ReadVLQ(Sequence);
                    return(JaiEventType.DELAY);

                /* Logical jumps */

                case (byte)JaiSeqEvent.JUMP:                   // Unconditional jump
                    State.jump_mode    = 0;                    // Set jump mode to 0
                    State.jump_address = Sequence.ReadInt32(); // Absolute address.
                    return(JaiEventType.JUMP);

                case (byte)JaiSeqEvent.JUMP_COND:                             // Jump based on mode
                    State.jump_mode    = Sequence.ReadByte();
                    State.jump_address = (int)Helpers.ReadUInt24BE(Sequence); // pointer
                    return(JaiEventType.JUMP);

                case (byte)JaiSeqEvent.RET_COND:
                    State.jump_mode = Sequence.ReadByte();

                    return(JaiEventType.RET);

                case (byte)JaiSeqEvent.CALL_COND:
                    State.jump_mode    = Sequence.ReadByte();
                    State.jump_address = (int)Helpers.ReadUInt24BE(Sequence);
                    return(JaiEventType.CALL);

                case (byte)JaiSeqEvent.RET:
                    return(JaiEventType.RET);



                /* Tempo Control */

                case (byte)JaiSeqEvent.J2_SET_ARTIC:     // The very same.
                {
                    var type = Sequence.ReadByte();
                    var val  = Sequence.ReadInt16();
                    if (type == 0x62)
                    {
                        State.ppqn = val;
                    }
                    return(JaiEventType.TIME_BASE);
                }

                case (byte)JaiSeqEvent.TIME_BASE:     // Set ticks per quarter note.
                    State.ppqn = (short)(Sequence.ReadInt16() - 40);
                    Console.WriteLine("Timebase ppqn set {0}", State.ppqn);
                    return(JaiEventType.TIME_BASE);

                case (byte)JaiSeqEvent.J2_TEMPO:  // Set BPM, Same format
                case (byte)JaiSeqEvent.TEMPO:     // Set BPM
                    State.bpm = Sequence.ReadInt16();
                    return(JaiEventType.TIME_BASE);

                /* Track Control */

                case (byte)JaiSeqEvent.OPEN_TRACK:
                    State.track_id      = Sequence.ReadByte();
                    State.track_address = (int)Helpers.ReadUInt24BE(Sequence);      // Pointer to track inside of BMS file (Absolute)
                    return(JaiEventType.NEW_TRACK);

                case (byte)JaiSeqEvent.FIN:
                    return(JaiEventType.HALT);

                case (byte)JaiSeqEvent.J2_SET_BANK:
                    State.voice_bank = Sequence.ReadByte();
                    return(JaiEventType.BANK_CHANGE);

                case (byte)JaiSeqEvent.J2_SET_PROG:
                    State.voice_program = Sequence.ReadByte();
                    return(JaiEventType.PROG_CHANGE);

                /* Parameter control */


                case (byte)JaiSeqEvent.J2_SET_PERF_8:
                    State.param       = Sequence.ReadByte();
                    State.param_value = Sequence.ReadByte();
                    return(JaiEventType.PARAM);

                case (byte)JaiSeqEvent.J2_SET_PERF_16:
                    State.param       = Sequence.ReadByte();
                    State.param_value = Sequence.ReadInt16();
                    return(JaiEventType.PARAM);

                case (byte)JaiSeqEvent.PARAM_SET_8:     // Set track parameters (Usually used for instruments)
                    State.param       = Sequence.ReadByte();
                    State.param_value = Sequence.ReadByte();
                    if (State.param == 0x20)   // 0x20 is bank change
                    {
                        State.voice_bank = (byte)State.param_value;
                        return(JaiEventType.BANK_CHANGE);
                    }
                    if (State.param == 0x21)     // 0x21 is program change
                    {
                        State.voice_program = (byte)State.param_value;
                        return(JaiEventType.PROG_CHANGE);
                    }
                    return(JaiEventType.PARAM);

                case (byte)JaiSeqEvent.PARAM_SET_16:     // Set track parameters (Usually used for instruments)
                    State.param       = Sequence.ReadByte();
                    State.param_value = Sequence.ReadInt16();
                    if (State.param == 0x20)     // 0x20 is bank change
                    {
                        State.voice_bank = (byte)State.param_value;
                        return(JaiEventType.BANK_CHANGE);
                    }
                    if (State.param == 0x21)     // 0x21 is program change
                    {
                        State.voice_program = (byte)State.param_value;
                        return(JaiEventType.PROG_CHANGE);
                    }
                    return(JaiEventType.PARAM);

                /* PERF Control*/

                /* Perf structure is as follows
                 * <byte> type
                 * <?> val
                 * (<?> dur)
                 */

                case (byte)JaiSeqEvent.PERF_U8_NODUR:
                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadByte();
                    State.perf_duration = 0;
                    State.perf_type     = 1;
                    State.perf_decimal  = ((double)State.perf_value / 0xFFd);
                    return(JaiEventType.PERF);

                case (byte)JaiSeqEvent.PERF_U8_DUR_U8:
                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadByte();
                    State.perf_duration = Sequence.ReadByte();
                    State.perf_type     = 1;
                    State.perf_decimal  = ((double)State.perf_value / 0xFFd);
                    return(JaiEventType.PERF);

                case (byte)JaiSeqEvent.PERF_U8_DUR_U16:

                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadByte();
                    State.perf_duration = Sequence.ReadUInt16();
                    State.perf_type     = 1;
                    State.perf_decimal  = ((double)State.perf_value / 0xFFd);
                    return(JaiEventType.PERF);

                case (byte)JaiSeqEvent.PERF_S8_NODUR:
                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadSByte();
                    State.perf_duration = 0;
                    State.perf_type     = 2;
                    State.perf_decimal  = ((double)(State.perf_value) / 0x7Fd);
                    return(JaiEventType.PERF);

                case (byte)JaiSeqEvent.PERF_S8_DUR_U8:
                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadSByte();
                    State.perf_duration = Sequence.ReadByte();
                    State.perf_type     = 2;
                    State.perf_decimal  = ((double)(State.perf_value) / 0x7Fd);
                    return(JaiEventType.PERF);

                case (byte)JaiSeqEvent.PERF_S8_DUR_U16:
                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadSByte();
                    State.perf_duration = Sequence.ReadUInt16();
                    State.perf_type     = 2;
                    State.perf_decimal  = ((double)(State.perf_value) / 0x7Fd);
                    return(JaiEventType.PERF);

                case (byte)JaiSeqEvent.PERF_S16_NODUR:
                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadInt16();
                    State.perf_duration = 0;
                    State.perf_type     = 3;
                    State.perf_decimal  = ((double)(State.perf_value) / 0x7FFFd);
                    return(JaiEventType.PERF);

                case (byte)JaiSeqEvent.PERF_S16_DUR_U8:
                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadInt16();
                    State.perf_duration = Sequence.ReadByte();
                    State.perf_type     = 3;
                    State.perf_decimal  = ((double)(State.perf_value) / 0x7FFFd);
                    return(JaiEventType.PERF);

                case (byte)JaiSeqEvent.PERF_S16_DUR_U16:
                    State.perf          = Sequence.ReadByte();
                    State.perf_value    = Sequence.ReadInt16();
                    State.perf_duration = Sequence.ReadUInt16();
                    State.perf_type     = 3;
                    State.perf_decimal  = ((double)(State.perf_value) / 0x7FFFd);
                    return(JaiEventType.PERF);


                /* J2 Opcodes */


                /* Unsure as of yet, but we have to keep alignment */

                case 0xDD:
                    skip(3);
                    return(JaiEventType.UNKNOWN);

                case 0xEF:
                case 0xF9:
                case 0xE6:
                case 0xE7:
                    skip(2);
                    return(JaiEventType.UNKNOWN);

                case 0xA0:
                case 0xA1:
                    skip(2);
                    return(JaiEventType.UNKNOWN);

                case 0xA3:
                    skip(2);
                    return(JaiEventType.UNKNOWN);

                case 0xA5:
                    skip(2);
                    return(JaiEventType.UNKNOWN);

                case 0xA7:
                    skip(2);
                    return(JaiEventType.UNKNOWN);

                case 0xA9:
                    skip(4);
                    return(JaiEventType.UNKNOWN);

                case 0xAA:
                    skip(4);
                    return(JaiEventType.UNKNOWN);

                case 0xAD:
                    skip(3);
                    return(JaiEventType.UNKNOWN);

                case 0xAE:
                    return(JaiEventType.UNKNOWN);

                case 0xB1:
                case 0xB2:
                case 0xB3:
                case 0xB4:
                case 0xB5:
                case 0xB6:
                case 0xB7:
                    int flag = Sequence.ReadByte();
                    if (flag == 0x40)
                    {
                        skip(2);
                    }
                    if (flag == 0x80)
                    {
                        skip(4);
                    }
                    return(JaiEventType.UNKNOWN);

                case 0xDB:

                case 0xDF:

                    skip(4);
                    return(JaiEventType.UNKNOWN);

                case 0xCB:
                case 0xBE:
                    skip(2);
                    return(JaiEventType.UNKNOWN);

                case 0xCC:
                    skip(2);
                    return(JaiEventType.UNKNOWN);

                case 0xCF:
                    skip(1);
                    return(JaiEventType.UNKNOWN);

                case 0xD0:
                case 0xD1:
                case 0xD2:
                case 0xD5:
                case 0xD9:

                case 0xDE:
                case 0xDA:

                    skip(1);
                    return(JaiEventType.UNKNOWN);

                case 0xF1:
                case 0xF4:



                case 0xD6:
                    skip(1);
                    return(JaiEventType.UNKNOWN);
                }
            }


            return(JaiEventType.UNKNOWN_ALIGN_FAIL);
        }