예제 #1
0
        public override void SerializeImpl(SerializerObject s)
        {
            NumChannels           = s.Serialize <ushort>(NumChannels, name: nameof(NumChannels));
            NumRowsPerPattern     = s.Serialize <ushort>(NumRowsPerPattern, name: nameof(NumRowsPerPattern));
            NumPatternsPerChannel = s.Serialize <ushort>(NumPatternsPerChannel, name: nameof(NumPatternsPerChannel));
            UShort_06             = s.Serialize <ushort>(UShort_06, name: nameof(UShort_06));
            Volume               = s.Serialize <ushort>(Volume, name: nameof(Volume));
            UShort_0A            = s.Serialize <ushort>(UShort_0A, name: nameof(UShort_0A));
            SequenceDataPointer  = s.SerializePointer(SequenceDataPointer, name: nameof(SequenceDataPointer));
            InstrumentSetPointer = s.SerializePointer(InstrumentSetPointer, name: nameof(InstrumentSetPointer));
            SampleSetPointer     = s.SerializePointer(SampleSetPointer, name: nameof(SampleSetPointer));
            SampleRate           = s.Serialize <ushort>(SampleRate, name: nameof(SampleRate));
            UShort_1A            = s.Serialize <ushort>(UShort_1A, name: nameof(UShort_1A));
            UShort_1C            = s.Serialize <ushort>(UShort_1C, name: nameof(UShort_1C));
            UShort_1E            = s.Serialize <ushort>(UShort_1E, name: nameof(UShort_1E));
            PatternTablePointers = s.SerializePointerArray(PatternTablePointers, NumChannels, name: nameof(PatternTablePointers));
            Reserved             = s.SerializeArray <uint>(Reserved, NumChannels, name: nameof(Reserved));

            List <int> instruments = new List <int>();

            if (PatternTable == null)
            {
                int instrumentCount = 0;
                PatternTable = new GAX2_PatternHeader[PatternTablePointers.Length][];
                Patterns     = new GAX2_Pattern[PatternTablePointers.Length][];
                for (int i = 0; i < PatternTablePointers.Length; i++)
                {
                    s.DoAt(PatternTablePointers[i], () => {
                        PatternTable[i] = s.SerializeObjectArray <GAX2_PatternHeader>(PatternTable[i], NumPatternsPerChannel, name: $"{nameof(PatternTable)}[{i}]");
                        if (Patterns[i] == null)
                        {
                            Patterns[i] = new GAX2_Pattern[PatternTable[i].Length];
                            for (int j = 0; j < Patterns[i].Length; j++)
                            {
                                s.DoAt(SequenceDataPointer + PatternTable[i][j].SequenceOffset, () => {
                                    Patterns[i][j]  = s.SerializeObject <GAX2_Pattern>(Patterns[i][j], onPreSerialize: t => t.Duration = NumRowsPerPattern, name: $"{nameof(Patterns)}[{i}][{j}]");
                                    instrumentCount = Math.Max(instrumentCount, Patterns[i][j].Rows.Max(cmd => cmd.Command == GAX2_PatternRow.Cmd.Note ? cmd.Instrument + 1 : 0));
                                    instruments.AddRange(Patterns[i][j].Rows.Where(cmd => cmd.Command == GAX2_PatternRow.Cmd.Note).Select(cmd => (int)cmd.Instrument));
                                });
                            }
                        }
                    });
                }
                InstrumentIndices = instruments.Distinct().Where(i => i != 250).ToArray();
                s.Log("Instrument Count: " + InstrumentIndices.Length);
                Pointer endOffset = Patterns.Max(ta => ta.Max(t => t.EndOffset));
                s.DoAt(endOffset, () => {
                    Name           = s.Serialize <string>(Name, name: nameof(Name));
                    string[] parse = Name.Split('"');
                    ParsedName     = parse[1];
                    ParsedArtist   = parse[2].Substring(3, 0xF);
                    s.Log(ParsedName + " - " + ParsedArtist);
                });
                s.DoAt(InstrumentSetPointer, () => {
                    InstrumentSet = s.SerializePointerArray <GAX2_Instrument>(InstrumentSet, instrumentCount, resolve: true, name: nameof(InstrumentSet));
                });
                Samples = new GAX2_Sample[InstrumentIndices.Length];
                for (int i = 0; i < InstrumentIndices.Length; i++)
                {
                    int ind   = InstrumentIndices[i];
                    var instr = InstrumentSet[ind].Value;
                    if (instr != null)
                    {
                        s.DoAt(SampleSetPointer + (instr.Sample) * 8, () => {
                            Samples[i] = s.SerializeObject <GAX2_Sample>(Samples[i], name: $"{nameof(Samples)}[{i}]");
                        });
                    }
                }
            }
        }
예제 #2
0
        private XM_PatternRow[] GetPatternRows(GAX2_Song song, int patternIndex, int channelIndex, int numRows)
        {
            GAX2_Pattern gax = song.Patterns[channelIndex][patternIndex];

            XM_PatternRow[] rows     = new XM_PatternRow[numRows];
            int             curRow   = 0;
            byte?           vol      = null;
            byte?           eff      = null;
            byte?           effParam = null;

            foreach (var row in gax.Rows)
            {
                switch (row.Command)
                {
                case GAX2_PatternRow.Cmd.StartTrack:
                    break;

                case GAX2_PatternRow.Cmd.EmptyTrack:
                    while (curRow < rows.Length)
                    {
                        rows[curRow++] = new XM_PatternRow();
                    }
                    break;

                // TODO: correct these
                case GAX2_PatternRow.Cmd.Unknown:
                    break;

                case GAX2_PatternRow.Cmd.EffectOnly:
                    eff            = (row.Effect < 16 && row.Effect != 14 && row.Effect != 12) ? (byte?)row.Effect : null;
                    effParam       = eff.HasValue ? (byte?)(row.Velocity) : null;
                    vol            = (row.Effect == 12) ? (byte?)(0x10 + (row.Velocity >> 2)) : null;
                    rows[curRow++] = new XM_PatternRow(volumeColumnByte: vol, effectType: eff, effectParameter: effParam);
                    break;

                case GAX2_PatternRow.Cmd.Unknown81:
                    rows[curRow++] = new XM_PatternRow();
                    break;

                case GAX2_PatternRow.Cmd.RestSingle:
                    rows[curRow++] = new XM_PatternRow();
                    break;

                case GAX2_PatternRow.Cmd.RestMultiple:
                    for (int i = 0; i < row.RestDuration; i++)
                    {
                        rows[curRow++] = new XM_PatternRow();
                    }
                    break;

                case GAX2_PatternRow.Cmd.Note:
                    eff      = (row.Effect < 16 && row.Effect != 14 && row.Effect != 12) ? (byte?)row.Effect : null;
                    effParam = eff.HasValue ? (byte?)(row.Velocity) : null;
                    vol      = (row.Effect == 12) ? (byte?)(0x10 + (row.Velocity >> 2)) : null;
                    if (row.Instrument == 250)
                    {
                        rows[curRow++] = new XM_PatternRow(note: 97, volumeColumnByte: vol, effectType: eff, effectParameter: effParam);
                    }
                    else
                    {
                        int instr = 1 + Array.IndexOf(song.InstrumentIndices, row.Instrument);
                        rows[curRow++] = new XM_PatternRow(note: row.Note, instrument: (byte)instr, volumeColumnByte: vol, effectType: eff, effectParameter: effParam);
                    }
                    break;
                }
            }
            return(rows);
        }
예제 #3
0
        private Track CreateTrack(GAX2_Song song, int trackNum)
        {
            Track t = new Track();
            TempoChangeBuilder b = new TempoChangeBuilder();

            b.Tempo = 500000;
            b.Build();
            t.Insert(0, b.Result);
            ChannelMessageBuilder builder = new ChannelMessageBuilder();
            int?lastNoteOn  = null;
            int currentTime = 0;
            int timeScale   = 5;

            t.EndOfTrackOffset = (song.Patterns[trackNum].Length * song.NumRowsPerPattern) * timeScale;
            for (int trackPiece = 0; trackPiece < song.Patterns[trackNum].Length; trackPiece++)
            {
                GAX2_Pattern gaxTrack = song.Patterns[trackNum][trackPiece];
                int          baseTime = trackPiece * song.NumRowsPerPattern;
                currentTime = baseTime;
                for (int i = 0; i < gaxTrack.Rows.Length; i++)
                {
                    GAX2_PatternRow cmd = gaxTrack.Rows[i];
                    switch (cmd.Command)
                    {
                    case GAX2_PatternRow.Cmd.Note:
                        if (cmd.Instrument == 250)
                        {
                            continue;
                        }
                        if (exportSingleSoundfont)
                        {
                            if (song.InstrumentSet[cmd.Instrument]?.Value == null || song.InstrumentSet[cmd.Instrument].Value.Sample >= 128)
                            {
                                continue;
                            }
                        }
                        else
                        {
                            if (song.InstrumentSet[cmd.Instrument]?.Value == null || Array.IndexOf(song.InstrumentIndices, cmd.Instrument) >= 128)
                            {
                                continue;
                            }
                        }
                        // Note off
                        if (lastNoteOn.HasValue)
                        {
                            builder.Command     = ChannelCommand.NoteOff;
                            builder.MidiChannel = 0;
                            builder.Data1       = lastNoteOn.Value;
                            builder.Data2       = 127;
                            builder.Build();
                            t.Insert(currentTime * timeScale, builder.Result);
                            lastNoteOn = null;
                        }
                        // Program change
                        {
                            int instrument = 0;
                            if (exportSingleSoundfont)
                            {
                                instrument = song.InstrumentSet[cmd.Instrument].Value.Sample;
                            }
                            else
                            {
                                instrument = Array.IndexOf(song.InstrumentIndices, cmd.Instrument);
                            }
                            builder.MidiChannel = 0;
                            builder.Command     = ChannelCommand.ProgramChange;
                            builder.Data1       = instrument;
                            builder.Build();
                            t.Insert(currentTime * timeScale, builder.Result);
                        }
                        // Note on
                        {
                            builder.Command = ChannelCommand.NoteOn;
                            int freq = cmd.Note;
                            int vel  = cmd.Velocity;
                            builder.Data1 = freq;      //GetMidiPitch(GetFrequency(freq));
                            float velf = (vel / 255f); // hack
                            int   veli = Mathf.RoundToInt(velf * 127f);
                            builder.Data2 = veli;
                            lastNoteOn    = builder.Data1;
                            builder.Build();
                            t.Insert(currentTime * timeScale, builder.Result);
                        }
                        break;
                    }
                    currentTime += cmd.Duration;
                }
            }
            if (lastNoteOn.HasValue)
            {
                builder.Command     = ChannelCommand.NoteOff;
                builder.MidiChannel = 0;
                builder.Data1       = lastNoteOn.Value;
                builder.Data2       = 127;
                builder.Build();
                t.Insert(currentTime * timeScale, builder.Result);
                lastNoteOn = null;
            }

            return(t);
        }