示例#1
0
        private List <MidiEvent> GenerateBeatTrack(List <XmkTimeSignature> timeSigs, MidiEventCollection mid)
        {
            List <MidiEvent> track = new List <MidiEvent>();

            track.Add(new NAudio.Midi.TextEvent("BEAT", MetaEventType.SequenceTrackName, 0));

            long lastEventOffset = mid.SelectMany(x => x).Select(y => y.AbsoluteTime).Max();
            long offset          = 0;

            var tsEndOffsets = timeSigs.Skip(1).Select(x => (long)(x.Ticks / 2)).ToList();

            tsEndOffsets.Add(lastEventOffset);

            int tsIdx = 0, currentBeat = 1;

            while (offset < lastEventOffset)
            {
                if (offset >= tsEndOffsets[tsIdx])
                {
                    // New time signature
                    currentBeat = 1;
                    tsIdx++;

                    offset = timeSigs[tsIdx].Ticks / 2;
                }

                var ts        = timeSigs[tsIdx];
                int beatSize  = DELTA_TICKS_PER_MEASURE / ts.Denominator;
                int eventSize = beatSize / 4;

                if (currentBeat > ts.Numerator)
                {
                    currentBeat = 1;
                }
                int pitch = currentBeat == 1 ? 12 : 13; // 12 = down, 13 = up

                // Adds beat event
                track.Add(new NoteEvent(offset, 1, MidiCommandCode.NoteOn, pitch, 1));
                track.Add(new NoteEvent(offset + eventSize, 1, MidiCommandCode.NoteOff, pitch, 1));

                currentBeat++;
                offset += beatSize;
            }

            // Adds end track
            track.Add(new MetaEvent(MetaEventType.EndTrack, 0, track.Last().AbsoluteTime));
            return(track);
        }
示例#2
0
    private void init(byte[] bytes)
    {
        Stream s = new MemoryStream(bytes);

        MidiFile midiFIle = new MidiFile(s);

        mDeltaTicks = midiFIle.DeltaTicksPerQuarterNote;

        MidiEventCollection     events    = midiFIle.Events;
        IEnumerable <MidiEvent> flattened = events.SelectMany(i => i);

        noteOns = flattened
                  .Where(midiEvent => midiEvent.CommandCode == MidiCommandCode.NoteOn)
                  .Select(m => m as NoteOnEvent);

        metaEvents = flattened
                     .Where(midiEvent => midiEvent.CommandCode == MidiCommandCode.MetaEvent)
                     .Select(m => m as MetaEvent);

        tempos = metaEvents
                 .Where(meta => meta.MetaEventType == MetaEventType.SetTempo)
                 .Select(m => m as TempoEvent);

        //let's assume one tempo for now
        //		TempoEvent firstTempo;
        if (tempos.Count() > 0)
        {
            mMicroSecondsPerQuarterNote = tempos.ToList()[0].MicrosecondsPerQuarterNote;
        }
        else
        {
            //120 bpm
            //minute / 120 quarter * microseconds/minute
            mMicroSecondsPerQuarterNote = 60000000 / 120;
        }
    }
示例#3
0
        public void Export(string path, bool remap = false)
        {
            MidiEventCollection mid = new MidiEventCollection(1, DELTA_TICKS_PER_QUARTER);

            _xmks.Sort((x, y) => GetSortNumber(x.Name) - GetSortNumber(y.Name));

            int GetSortNumber(string name)
            {
                switch (name)
                {
                case "touchdrums":
                    return(1);

                case "touchguitar":
                    return(2);

                case "guitar_3x2":
                    return(3);

                case "vocals":
                    return(4);

                case "control":
                    return(5);

                default:
                    return(100);
                }
            }

            Xmk firstXmk = _xmks.FirstOrDefault();

            mid.AddTrack(CreateTempoTrack(firstXmk.TempoEntries, firstXmk.TimeSignatureEntries));

            if (!remap)
            {
                for (int i = 0; i < _xmks.Count; i++)
                {
                    mid.AddTrack(CreateTrack(_xmks[i], i));
                }
            }
            else
            {
                var eventsIdx = -1;
                for (int i = 0; i < _xmks.Count; i++)
                {
                    Xmk    xmk       = _xmks[i];
                    string trackName = !string.IsNullOrEmpty(xmk.Name) ? xmk.Name : $"NOTES {i}";

                    // Sets remapping and track name
                    switch (trackName.ToLower())
                    {
                    case "control":
                        // EVENTS
                        mid.AddTrack(ParseEvents(xmk));
                        eventsIdx = i + 1;
                        continue;

                    case "guitar_3x2":
                        // PART GUITAR GHL
                        mid.AddTrack(ParseGuitar3(xmk));
                        continue;

                    case "touchdrums":
                        // PART DRUMS
                        mid.AddTrack(ParseDrums(xmk));
                        continue;

                    case "touchguitar":
                        // PART GUITAR
                        mid.AddTrack(ParseGuitar6(xmk));
                        continue;

                    case "vocals":
                        // PART VOCALS
                        mid.AddTrack(ParseVocals(xmk));
                        continue;
                    }

                    mid.AddTrack(CreateTrack(xmk, i));
                }

                // Updates EVENTS track
                var firstPlay = mid.SelectMany(x => x)
                                .Where(y => y is TextEvent && ((TextEvent)y).Text == "[play]")
                                .OrderBy(z => z.AbsoluteTime)
                                .FirstOrDefault();

                var lastIdle = mid.SelectMany(x => x)
                               .Where(y => y is TextEvent && ((TextEvent)y).Text == "[idle]")
                               .OrderByDescending(z => z.AbsoluteTime)
                               .FirstOrDefault();

                if (eventsIdx != -1 && firstPlay != null)
                {
                    var events       = mid[eventsIdx];
                    var nextEvent    = events.OrderBy(x => x.AbsoluteTime).First(y => y.AbsoluteTime > firstPlay.AbsoluteTime);
                    var nextEventIdx = events.IndexOf(nextEvent);

                    events.Insert(nextEventIdx, new TextEvent("[music_start]", MetaEventType.TextEvent, firstPlay.AbsoluteTime));
                }

                if (eventsIdx != -1 && lastIdle != null)
                {
                    var events   = mid[eventsIdx];
                    var trackEnd = events.Last();
                    trackEnd.AbsoluteTime = lastIdle.AbsoluteTime; // Updates end track position
                    events.Remove(trackEnd);

                    events.Add(new TextEvent("[music_end]", MetaEventType.TextEvent, lastIdle.AbsoluteTime));
                    events.Add(new TextEvent("[end]", MetaEventType.TextEvent, lastIdle.AbsoluteTime));
                    events.Add(trackEnd); // Adds end track back
                }

                // Generates up/down events for BEAT track (Needed for beat markers in CH and OD in RB)
                mid.AddTrack(GenerateBeatTrack(firstXmk.TimeSignatureEntries, mid));
            }

            MidiFile.Export(path, mid);
        }
示例#4
0
        public void Export(string path)
        {
            MidiEventCollection mid = new MidiEventCollection(1, DELTA_TICKS_PER_QUARTER);

            _xmks.Sort((x, y) => GetSortNumber(x.Name) - GetSortNumber(y.Name));

            int GetSortNumber(string name)
            {
                switch (name)
                {
                case "touchdrums":
                    return(1);

                case "touchguitar":
                    return(2);

                case "guitar_3x2":
                    return(3);

                case "vocals":
                    return(4);

                case "control":
                    return(5);

                default:
                    return(100);
                }
            }

            // Get xmk track to use for tempo map + generating BEAT track
            // Note: Avoiding "touchdrums" because it was an under-developed feature so it may not consistently be as accurate compared to 6 fret
            var tempoTrackPreference = new[] { "guitar_3x2", "touchguitar", "vocals", "control" };
            Xmk firstXmk             = _xmks
                                       .Select(x =>
            {
                var idx = Array.FindIndex(tempoTrackPreference, y => y == x.Name);
                if (idx == -1)
                {
                    idx = 100;
                }

                return(Xmk: x, Order: idx);
            })
                                       .OrderBy(x => x.Order)
                                       .Select(x => x.Xmk)
                                       .First();

            mid.AddTrack(CreateTempoTrack(firstXmk.TempoEntries, firstXmk.TimeSignatureEntries));

            if (!_exportOptions.Remap)
            {
                for (int i = 0; i < _xmks.Count; i++)
                {
                    mid.AddTrack(CreateTrack(_xmks[i], i));
                }
            }
            else
            {
                var eventsIdx = -1;
                for (int i = 0; i < _xmks.Count; i++)
                {
                    Xmk    xmk       = _xmks[i];
                    string trackName = !string.IsNullOrEmpty(xmk.Name) ? xmk.Name : $"NOTES {i}";

                    // Sets remapping and track name
                    switch (trackName.ToLower())
                    {
                    case "control":
                        // EVENTS
                        mid.AddTrack(ParseEvents(xmk));
                        eventsIdx = i + 1;
                        continue;

                    case "guitar_3x2":
                        // PART GUITAR GHL
                        mid.AddTrack(ParseGuitar3(xmk));
                        continue;

                    case "touchdrums":
                        // PART DRUMS
                        mid.AddTrack(ParseDrums(xmk));
                        continue;

                    case "touchguitar":
                        // PART GUITAR
                        mid.AddTrack(ParseGuitar5(xmk));
                        continue;

                    case "vocals":
                        // PART VOCALS
                        mid.AddTrack(ParseVocals(xmk));
                        continue;
                    }

                    // TODO: Refactor to be more elegant
                    if (_voxRegex.IsMatch(trackName))
                    {
                        mid.AddTrack(ParseVocals(xmk));
                        continue;
                    }

                    mid.AddTrack(CreateTrack(xmk, i));
                }

                // Updates EVENTS track
                var firstPlay = mid.SelectMany(x => x)
                                .Where(y => y is TextEvent && ((TextEvent)y).Text == "[play]")
                                .OrderBy(z => z.AbsoluteTime)
                                .FirstOrDefault();

                var lastIdle = mid.SelectMany(x => x)
                               .Where(y => y is TextEvent && ((TextEvent)y).Text == "[idle]")
                               .OrderByDescending(z => z.AbsoluteTime)
                               .FirstOrDefault();

                if (eventsIdx != -1 && firstPlay != null)
                {
                    var events    = mid[eventsIdx];
                    var nextEvent = events
                                    .OrderBy(y => y.AbsoluteTime)
                                    .FirstOrDefault(z => z.AbsoluteTime > firstPlay.AbsoluteTime);

                    // If nextEvent is null, assume no text events exist
                    var nextEventIdx = (nextEvent is null)
                        ? 1
                        : events.IndexOf(nextEvent);

                    events.Insert(nextEventIdx, new TextEvent("[music_start]", MetaEventType.TextEvent, firstPlay.AbsoluteTime));
                }

                if (eventsIdx != -1 && lastIdle != null)
                {
                    var events   = mid[eventsIdx];
                    var trackEnd = events.Last();
                    trackEnd.AbsoluteTime = lastIdle.AbsoluteTime; // Updates end track position
                    events.Remove(trackEnd);

                    events.Add(new TextEvent("[music_end]", MetaEventType.TextEvent, lastIdle.AbsoluteTime));
                    events.Add(new TextEvent("[end]", MetaEventType.TextEvent, lastIdle.AbsoluteTime));
                    events.Add(trackEnd); // Adds end track back
                }

                // Generates up/down events for BEAT track (Needed for beat markers in CH and OD in RB)
                mid.AddTrack(GenerateBeatTrack(firstXmk.TimeSignatureEntries, mid));
            }

            MidiFile.Export(path, mid);
        }