Exemplo n.º 1
0
        public void AddMetaData()
        {
            //create metadata track
            Track t = new Track();

            byte[] tempo              = new byte[3];
            int    ms_per_min         = 60000000;
            int    ms_per_quarternote = ms_per_min / FBPM;

            tempo[0] = (byte)((ms_per_quarternote >> 16) & byte.MaxValue);
            tempo[1] = (byte)((ms_per_quarternote >> 8) & byte.MaxValue);
            tempo[2] = (byte)(ms_per_quarternote & byte.MaxValue);
            TempoChangeBuilder tcBuilder = new TempoChangeBuilder(new MetaMessage(MetaType.Tempo, tempo));

            tcBuilder.Build();
            t.Insert(1, tcBuilder.Result);

            byte[] timesignature = new byte[4];
            timesignature[0] = FTimeSignature.Numerator;
            timesignature[1] = (byte)Math.Log(FTimeSignature.Denominator, 2);
            timesignature[2] = FTimeSignature.MetronomePulse;
            timesignature[3] = FTimeSignature.NumberOf32nds;
            TimeSignatureBuilder tsBuilder = new TimeSignatureBuilder(new MetaMessage(MetaType.TimeSignature, timesignature));

            tsBuilder.Build();
            t.Insert(2, tsBuilder.Result);

            FSequence.Add(t);
        }
Exemplo n.º 2
0
    public void Process(MetaMessage message)
    {
        #region Require

        if (message == null)
        {
            throw new ArgumentNullException("message");
        }

        #endregion

        #region Guard

        if (message.MetaType != MetaType.Tempo)
        {
            return;
        }

        #endregion

        TempoChangeBuilder builder = new TempoChangeBuilder(message);

        // Set the new tempo.
        Tempo = builder.Tempo;
        Tempo = Tempo;
    }
Exemplo n.º 3
0
 private void OnMetaMessagePlayed(object sender, MetaMessageEventArgs e)
 {
     if (e.Message.MetaType == MetaType.Tempo)
     {
         TempoChangeBuilder builder = new TempoChangeBuilder(e.Message);
         midiTempo = (60000000 / builder.Tempo);
         OnTempoChange?.Invoke(this, midiTempo);
     }
     if (e.Message.MetaType == MetaType.Lyric)
     {
         MetaTextBuilder builder = new MetaTextBuilder(e.Message);
         if (e.MidiTrack == LoadedTrack)
         {
             OnLyric?.Invoke(this, builder.Text);
         }
     }
     if (e.Message.MetaType == MetaType.TrackName)
     {
         MetaTextBuilder builder = new MetaTextBuilder(e.Message);
         ParseTrackName(e.MidiTrack, builder.Text);
         if (e.MidiTrack == LoadedTrack)
         {
             OnTrackNameChange?.Invoke(this, builder.Text);
         }
     }
     if (e.Message.MetaType == MetaType.InstrumentName)
     {
         MetaTextBuilder builder = new MetaTextBuilder(e.Message);
         OnTrackNameChange?.Invoke(this, builder.Text);
         Console.WriteLine("Instrument name: " + builder.Text);
     }
 }
Exemplo n.º 4
0
        public MetaMessage BuildMessage()
        {
            var b = new TempoChangeBuilder();

            b.Tempo = (int)Tempo;
            b.Build();
            return(b.Result);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Adds a MIDI message which sets the tempo
        /// </summary>
        /// <param name="tempoBPM">Tempo in BPM</param>
        public void SetTempo(int tempoBPM)
        {
            TempoChangeBuilder builder = new TempoChangeBuilder
            {
                Tempo = 60000000 / tempoBPM // convert to PPQ
            };

            builder.Build();
            QueueMessage(builder.Result);
        }
Exemplo n.º 6
0
        private Sequence CreateSequence()
        {
            if (tunes == null || tunes.Count < 2)
            {
                return(null);
            }

            selectedTune = 1;

            SetDefaultValues();
            nextNote = TimeSpan.Zero;
            SetHeaderValues();
            SetHeaderValues(selectedTune, true);
            StartMeasure();

            sequence        = new Sequence(Ppqn);
            sequence.Format = 1;
            metaTrack       = new Track();
            mainTrack       = new Track();
            sequence.Add(metaTrack);
            TempoChangeBuilder tempoBuilder = new TempoChangeBuilder();

            tempoBuilder.Tempo = Tempo;
            tempoBuilder.Build();
            metaTrack.Insert(0, tempoBuilder.Result);
            TimeSignatureBuilder timeBuilder = new TimeSignatureBuilder();

            timeBuilder.Numerator   = timeSigNumerator;
            timeBuilder.Denominator = timeSigDenominator;
            timeBuilder.Build();
            metaTrack.Insert(0, timeBuilder.Result);
            sequence.Add(mainTrack);

            MetaTextBuilder textBuilder = new MetaTextBuilder();

            textBuilder.Type = MetaType.TrackName;
            textBuilder.Text = "Tempo Track";
            textBuilder.Build();
            metaTrack.Insert(0, textBuilder.Result);

            textBuilder      = new MetaTextBuilder();
            textBuilder.Type = MetaType.TrackName;
            textBuilder.Text = "Tune 1";
            textBuilder.Build();
            mainTrack.Insert(0, textBuilder.Result);

            while (tokenIndex < tokens.Count)
            {
                AddNextNote();
            }

            return(sequence);
        }
Exemplo n.º 7
0
 public GuitarTempo(GuitarMessageList owner, MidiEvent ev)
     : base(owner, ev, null, GuitarMessageType.GuitarTempo)
 {
     if (ev == null)
     {
         this.Tempo = Utility.DummyTempo;
     }
     else
     {
         var cb = new TempoChangeBuilder((MetaMessage)ev.Clone());
         this.Tempo = cb.Tempo;
     }
 }
Exemplo n.º 8
0
        public float GetTimeFromTick(int tick)
        {
            if (tick <= 0)
            {
                return(0f);
            }

            float ms  = 0f;
            int   mul = midiTempo;

            List <Track> trackEnumsToRemove = new List <Track>();
            Dictionary <Track, IEnumerator <MidiEvent> > trackEnums = new Dictionary <Track, IEnumerator <MidiEvent> >();

            foreach (Track t in Sequence)
            {
                var en = t.Iterator().GetEnumerator();
                if (en.MoveNext())
                {
                    trackEnums.Add(t, en);
                }
            }

            for (int i = 0; i < tick; i++)
            {
                foreach (KeyValuePair <Track, IEnumerator <MidiEvent> > tem in trackEnums)
                {
                    if (tem.Value == null)
                    {
                        continue;
                    }
                    Track tek = tem.Key;
                    IEnumerator <MidiEvent> ten = tem.Value;
                    MidiEvent ev  = ten.Current;
                    bool      end = false;
                    while (ten.Current.AbsoluteTicks < i)
                    {
                        if (!ten.MoveNext())
                        {
                            end = true;
                            break;
                        }
                    }
                    if (ten.Current != ev)
                    {
                        // New event, apply
                        if (ev.MidiMessage is MetaMessage)
                        {
                            MetaMessage msg = ev.MidiMessage as MetaMessage;
                            if (msg.MetaType == MetaType.Tempo)
                            {
                                TempoChangeBuilder builder = new TempoChangeBuilder(msg);
                                mul = (int)((60000000 / builder.Tempo) * Speed);
                            }
                        }
                    }
                    if (end)
                    {
                        trackEnumsToRemove.Add(tek);
                    }
                }
                if (trackEnumsToRemove.Count > 0)
                {
                    foreach (Track t in trackEnumsToRemove)
                    {
                        trackEnums.Remove(t);
                    }
                    trackEnumsToRemove.Clear();
                }
                ms += 1 * (60000f / (float)(mul * Sequence.Division));
            }
            return(ms);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Creates a notechart from the specified midi path and the actual charttype
        /// (i.e. ExpertSingle from notes.mid).  Due to the overhead necessary to
        /// parse a midi file.  I am going to cram all midi->chart operations into
        /// one function call.
        /// This function uses the Sanford midi parser.  While it is horribly slow
        /// on larger (e.g. RB) midis, it works without a hitch on every midi I've
        /// come across.
        /// </summary>
        /// <param name="chartSelection">
        /// The information on which particular notechart to use.
        /// </param>
        /// <param name="chartInfo">The metadata on the chart.</param>
        /// <param name="BPMChanges">The list of BPM changes for this chart.</param>
        /// <returns>
        /// A filled out Notechart containing the needed information from the *.mid file.
        /// </returns>
        public static Notes ParseMidiInformationSanford(ChartSelection chartSelection,
                                                        Info chartInfo,
                                                        List <BPMChange> BPMChanges)
        {
            Notes notechartToReturn = new Notes();

            notechartToReturn.instrument = chartSelection.instrument;
            notechartToReturn.difficulty = chartSelection.difficulty;

            // The following two switch's are used to get the proper midi terminology for
            // the selected track and difficulty.
            string instrumentPart = null;
            int    greenKey       = 0;
            int    redKey         = 0;
            int    yellowKey      = 0;
            int    blueKey        = 0;
            int    orangeKey      = 0;

            switch (chartSelection.instrument)
            {
            case "Single":
                instrumentPart = "PART GUITAR";
                break;

            case "DoubleGuitar":
                instrumentPart = "PART GUITAR COOP";
                break;

            case "DoubleBass":
                instrumentPart = "PART BASS";
                break;

            case "Drums":
                instrumentPart = "PART DRUMS";
                break;

            default:
                instrumentPart = "PART GUITAR";
                break;
            }

            switch (chartSelection.difficulty)
            {
            case "Expert":
                greenKey  = 96;
                redKey    = 97;
                yellowKey = 98;
                blueKey   = 99;
                orangeKey = 100;
                break;

            case "Hard":
                greenKey  = 84;
                redKey    = 85;
                yellowKey = 86;
                blueKey   = 87;
                orangeKey = 88;
                break;

            case "Medium":
                greenKey  = 72;
                redKey    = 73;
                yellowKey = 74;
                blueKey   = 75;
                orangeKey = 76;
                break;

            case "Easy":
                greenKey  = 60;
                redKey    = 61;
                yellowKey = 62;
                blueKey   = 63;
                orangeKey = 64;
                break;

            default:
                greenKey  = 96;
                redKey    = 97;
                yellowKey = 98;
                blueKey   = 99;
                orangeKey = 100;
                break;
            }

            Sequence mySequence = new Sequence(chartSelection.directory + "\\notes.mid");
            Track    trackToUse = new Track();

            chartInfo.resolution = mySequence.Division;

            // Go through each event in the first track (which contains the BPM changes)
            // and parse the resulting string.
            Track sanTrack = mySequence[0];

            foreach (Sanford.Multimedia.Midi.MidiEvent currEvent in sanTrack.Iterator())
            {
                if (currEvent.MidiMessage.MessageType == MessageType.Meta)
                {
                    MetaMessage currMessage = currEvent.MidiMessage as MetaMessage;
                    //currTickValue += Convert.ToUInt32(splitEventString[1]);
                    if (currMessage.MetaType == MetaType.Tempo)
                    {
                        TempoChangeBuilder tempoBuilder = new TempoChangeBuilder(currMessage);
                        int midiBPMChange = tempoBuilder.Tempo;
                        // In midi files, bpm chages are stored as "microseconds per quarter note"
                        // and must be converted to BPM, and then into the non decimal format the game
                        // uses.
                        double currBPMDouble = 60000000 / (double)midiBPMChange;
                        uint   BPMToAdd      = (uint)(currBPMDouble * 1000);
                        BPMChanges.Add(new BPMChange((uint)currEvent.AbsoluteTicks, (uint)BPMToAdd));
                    }
                }
            }

            // Find the specified instrument's track
            for (int i = 1; i < mySequence.Count; i++)
            {
                sanTrack = mySequence[i];
                Sanford.Multimedia.Midi.MidiEvent currEvent = sanTrack.GetMidiEvent(0);
                if (currEvent.MidiMessage.MessageType == MessageType.Meta)
                {
                    MetaMessage currMessage = currEvent.MidiMessage as MetaMessage;
                    if (currMessage.MetaType == MetaType.TrackName)
                    {
                        MetaTextBuilder trackName = new MetaTextBuilder(currMessage);

                        // -If we come across a "T1 GEMS" track, we're in GH1 territory.
                        // -GH2/FoF has both PART BASS and PART RHYTHM (one or the other depending
                        //  on the chart).
                        if ((trackName.Text == instrumentPart) || (trackName.Text == "T1 GEMS") ||
                            ((trackName.Text == "PART RHYTHM") && (instrumentPart == "PART BASS")))
                        {
                            trackToUse = sanTrack;
                        }
                    }
                }
            }

            Note currNote  = new Note();
            bool blankNote = true;

            // Scan through and record every note specific to the selected difficulty
            foreach (Sanford.Multimedia.Midi.MidiEvent currEvent in trackToUse.Iterator())
            {
                // We need to specify wether a note is blank or not so we don't add
                // blank notes from other difficulties into the chart, but if we have
                // a filled out note, any nonzero tick value means we are moving to a
                // new note, so we must cut our ties and add this note to the chart.
                if ((currEvent.DeltaTicks != 0) && !blankNote)
                {
                    notechartToReturn.notes.Add(currNote);
                    currNote  = new Note();
                    blankNote = true;
                }

                if (currEvent.MidiMessage.MessageType == MessageType.Channel)
                {
                    ChannelMessage currMessage = currEvent.MidiMessage as ChannelMessage;
                    if (currMessage.Command == ChannelCommand.NoteOn)
                    {
                        // Only consider notes within the octave our difficulty is in.
                        if (((currMessage.Data1 == greenKey) || (currMessage.Data1 == redKey) ||
                             (currMessage.Data1 == yellowKey) || (currMessage.Data1 == blueKey) ||
                             (currMessage.Data1 == orangeKey)) && (currMessage.Data2 != 0))
                        {
                            // If it's a new note, we need to setup the tick value of it.
                            if (blankNote)
                            {
                                //currNote.TickValue = totalTickValue;
                                currNote.tickValue = (uint)currEvent.AbsoluteTicks;
                                blankNote          = false;
                            }
                            if (currMessage.Data1 == greenKey)
                            {
                                currNote.addNote(0);
                            }
                            else if (currMessage.Data1 == redKey)
                            {
                                currNote.addNote(1);
                            }
                            else if (currMessage.Data1 == yellowKey)
                            {
                                currNote.addNote(2);
                            }
                            else if (currMessage.Data1 == blueKey)
                            {
                                currNote.addNote(3);
                            }
                            else if (currMessage.Data1 == orangeKey)
                            {
                                currNote.addNote(4);
                            }
                        }
                    }
                }
            }

            return(notechartToReturn);
        }
Exemplo n.º 10
0
        public override void SaveAsMIDI(string fileName)
        {
            if (NumTracks == 0)
            {
                throw new InvalidDataException("Questa canzone non ha tracce.");
            }

            CalculateTicks();
            var midi = new Sequence(96)
            {
                Format = 1
            };
            var metaTrack = new Sanford.Multimedia.Midi.Track();

            midi.Add(metaTrack);

            for (int i = 0; i < NumTracks; i++)
            {
                var track = new Sanford.Multimedia.Midi.Track();
                midi.Add(track);

                FreeNoteCommand freeNote    = null;
                MidiEvent       freeNoteOff = null;

                for (int j = 0; j < Commands[i].Count; j++)
                {
                    var e = Commands[i][j];

                    // Extended note ended ended and wasn't renewed
                    if (freeNoteOff != null && freeNoteOff.AbsoluteTicks < e.AbsoluteTicks * 2)
                    {
                        freeNote    = null;
                        freeNoteOff = null;
                    }

                    if (e.Command is VolumeCommand vol)
                    {
                        track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Volume, vol.Volume / 2));
                    }
                    else if (e.Command is VoiceCommand voice)
                    {
                        // TODO: Fork and remove restriction
                        track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.ProgramChange, i, voice.Voice & 0x7F));
                    }
                    else if (e.Command is PanpotCommand pan)
                    {
                        track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Pan, pan.Panpot / 2 + 0x40));
                    }
                    else if (e.Command is BendCommand bend)
                    {
                        track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.PitchWheel, i, 0, bend.Bend / 2 + 0x40));
                    }
                    else if (e.Command is BendRangeCommand bendr)
                    {
                        track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.Controller, i, 20, bendr.Range / 2));
                    }
                    else if (e.Command is MLSSNoteCommand note)
                    {
                        // Extended note is playing and it should be extended by this note
                        if (freeNote != null && freeNote.Note - 0x80 == note.Note)
                        {
                            // Move the note off command
                            track.Move(freeNoteOff, freeNoteOff.AbsoluteTicks + note.Duration * 2);
                        }
                        // Extended note is playing but this note is different OR there is no extended note playing
                        // Either way we play a new note and forget that one
                        else
                        {
                            track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.NoteOn, i, note.Note, 0x7F));
                            track.Insert(e.AbsoluteTicks * 2 + note.Duration * 2, new ChannelMessage(ChannelCommand.NoteOff, i, note.Note));
                            freeNote    = null;
                            freeNoteOff = null;
                        }
                    }
                    else if (e.Command is FreeNoteCommand free)
                    {
                        // Extended note is playing and it should be extended
                        if (freeNote != null && freeNote.Note == free.Note)
                        {
                            // Move the note off command
                            track.Move(freeNoteOff, freeNoteOff.AbsoluteTicks + free.Duration * 2);
                        }
                        // Extended note is playing but this note is different OR there is no extended note playing
                        // Either way we play a new note and forget that one
                        else
                        {
                            track.Insert(e.AbsoluteTicks * 2, new ChannelMessage(ChannelCommand.NoteOn, i, free.Note - 0x80, 0x7F));
                            track.Insert(e.AbsoluteTicks * 2 + free.Duration * 2, new ChannelMessage(ChannelCommand.NoteOff, i, free.Note - 0x80));
                            freeNote    = free;
                            freeNoteOff = track.GetMidiEvent(track.Count - 2); // -1 would be the end of track event
                        }
                    }
                    else if (i == 0 && e.Command is TempoCommand tempo)
                    {
                        var change = new TempoChangeBuilder {
                            Tempo = (60000000 / tempo.Tempo)
                        };
                        change.Build();
                        metaTrack.Insert(e.AbsoluteTicks * 2, change.Result);
                    }
                    else if (i == 0 && e.Command is GoToCommand goTo)
                    {
                        int jumpCmd = Commands[i].FindIndex(c => c.GetOffset() == goTo.Offset);
                        metaTrack.Insert(Commands[i][jumpCmd].AbsoluteTicks * 2, new MetaMessage(MetaType.Marker, new byte[] { (byte)'[' }));
                        metaTrack.Insert(e.AbsoluteTicks * 2, new MetaMessage(MetaType.Marker, new byte[] { (byte)']' }));
                    }
                    else if (e.Command is FinishCommand fine)
                    {
                        // TODO: Fix ticks before end of track event
                        // Library automatically is updating track.EndOfTrackOffset for us
                        break;
                    }
                }
            }
            midi.Save(fileName);
        }
Exemplo n.º 11
0
        public override void SaveAsMIDI(string fileName)
        {
            if (NumTracks == 0)
            {
                throw new InvalidDataException("Questa canzone non ha tracce.");
            }

            CalculateTicks();
            var midi = new Sequence(24)
            {
                Format = 1
            };
            var metaTrack = new Sanford.Multimedia.Midi.Track();

            midi.Add(metaTrack);

            for (int i = 0; i < NumTracks; i++)
            {
                var track = new Sanford.Multimedia.Midi.Track();
                midi.Add(track);

                int endOfPattern = 0, startOfPatternTicks = 0, endOfPatternTicks = 0, shift = 0;
                var playing = new List <M4ANoteCommand>();

                for (int j = 0; j < Commands[i].Count; j++)
                {
                    var e     = Commands[i][j];
                    int ticks = e.AbsoluteTicks + (endOfPatternTicks - startOfPatternTicks);

                    if (e.Command is KeyShiftCommand keysh)
                    {
                        shift = keysh.Shift;
                    }
                    else if (e.Command is M4ANoteCommand note)
                    {
                        int n = (note.Note + shift).Clamp(0, 0x7F);
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.NoteOn, i, n, note.Velocity));
                        if (note.Duration != -1)
                        {
                            track.Insert(ticks + note.Duration, new ChannelMessage(ChannelCommand.NoteOff, i, n));
                        }
                        else
                        {
                            playing.Add(note);
                        }
                    }
                    else if (e.Command is EndOfTieCommand eot)
                    {
                        M4ANoteCommand nc = null;

                        if (eot.Note == -1)
                        {
                            nc = playing.LastOrDefault();
                        }
                        else
                        {
                            nc = playing.LastOrDefault(n => n.Note == eot.Note);
                        }

                        if (nc != null)
                        {
                            int no = (nc.Note + shift).Clamp(0, 0x7F);
                            track.Insert(ticks, new ChannelMessage(ChannelCommand.NoteOff, i, no));
                            playing.Remove(nc);
                        }
                    }
                    else if (e.Command is VoiceCommand voice)
                    {
                        // TODO: Fork and remove restriction
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.ProgramChange, i, voice.Voice & 0x7F));
                    }
                    else if (e.Command is VolumeCommand vol)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Volume, vol.Volume));
                    }
                    else if (e.Command is PanpotCommand pan)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Pan, pan.Panpot + 0x40));
                    }
                    else if (e.Command is BendCommand bend)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.PitchWheel, i, 0, bend.Bend + 0x40));
                    }
                    else if (e.Command is BendRangeCommand bendr)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 20, bendr.Range));
                    }
                    else if (e.Command is LFOSpeedCommand lfos)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 21, lfos.Speed));
                    }
                    else if (e.Command is LFODelayCommand lfodl)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 26, lfodl.Delay));
                    }
                    else if (e.Command is ModDepthCommand mod)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.ModulationWheel, mod.Depth));
                    }
                    else if (e.Command is ModTypeCommand modt)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 22, modt.Type));
                    }
                    else if (e.Command is TuneCommand tune)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 24, tune.Tune));
                    }
                    else if (e.Command is TempoCommand tempo)
                    {
                        var change = new TempoChangeBuilder {
                            Tempo = (60000000 / tempo.Tempo)
                        };
                        change.Build();
                        metaTrack.Insert(ticks, change.Result);
                    }
                    else if (e.Command is CallCommand patt)
                    {
                        int callCmd = Commands[i].FindIndex(c => c.GetOffset() == patt.Offset);
                        endOfPattern      = j;
                        endOfPatternTicks = e.AbsoluteTicks;
                        j = callCmd - 1; // -1 for incoming ++
                        startOfPatternTicks = Commands[i][j + 1].AbsoluteTicks;
                    }
                    else if (e.Command is ReturnCommand)
                    {
                        if (endOfPattern != 0)
                        {
                            j            = endOfPattern;
                            endOfPattern = startOfPatternTicks = endOfPatternTicks = 0;
                        }
                    }
                    else if (i == 0 && e.Command is GoToCommand goTo)
                    {
                        int jumpCmd = Commands[i].FindIndex(c => c.GetOffset() == goTo.Offset);
                        metaTrack.Insert(Commands[i][jumpCmd].AbsoluteTicks, new MetaMessage(MetaType.Marker, new byte[] { (byte)'[' }));
                        metaTrack.Insert(ticks, new MetaMessage(MetaType.Marker, new byte[] { (byte)']' }));
                    }
                    else if (e.Command is FinishCommand fine)
                    {
                        // TODO: Fix ticks before end of track event
                        // Library automatically is updating track.EndOfTrackOffset for us
                        break;
                    }
                }
            }
            midi.Save(fileName);
        }
Exemplo n.º 12
0
        private Track CreateTrack(R1Jaguar_MusicDescriptor jagFile)
        {
            Track t = new Track();
            TempoChangeBuilder b = new TempoChangeBuilder();

            b.Tempo = 22000;
            b.Build();
            t.Insert(0, b.Result);
            ChannelMessageBuilder builder          = new ChannelMessageBuilder();
            Dictionary <int, int> curNoteOnChannel = new Dictionary <int, int>();
            int timeScale = 1;

            for (int i = 0; i < jagFile.MusicData.Length; i++)
            {
                R1Jaguar_MusicData e = jagFile.MusicData[i];
                if (e.Time != int.MaxValue)
                {
                    int channelByte = BitHelpers.ExtractBits(e.Command, 8, 24);
                    if (channelByte == 0x7F)                       // special point in the song
                    {
                        int idByte = BitHelpers.ExtractBits(e.Command, 8, 0);
                        if (idByte == 0xFF && i >= jagFile.MusicData.Length - 2)                           // End point
                        {
                            t.EndOfTrackOffset = e.Time / timeScale;
                            break;
                        }
                        else
                        {
                            // Loop point, or command to return to loop point
                        }
                    }
                    else
                    {
                        int channel = BitHelpers.ExtractBits(e.Command, 4, 26);
                        int command = BitHelpers.ExtractBits(e.Command, 1, 31);
                        if (command == 1)
                        {
                            // Note off
                            if (curNoteOnChannel.ContainsKey(channel))
                            {
                                builder.Command = ChannelCommand.NoteOff;
                                int note = curNoteOnChannel.TryGetValue(channel, out int val) ? val : 0;
                                if (note >= 128)
                                {
                                    builder.MidiChannel = 9;
                                    builder.Data1       = note - 128;
                                }
                                else
                                {
                                    builder.MidiChannel = channel;
                                    builder.Data1       = note;
                                }
                                builder.Data2 = 127;
                                builder.Build();
                                t.Insert(e.Time / timeScale, builder.Result);
                            }

                            // Program change
                            int instrument = BitHelpers.ExtractBits(e.Command, 5, 21);
                            if (PercussionInstruments[instrument] != Percussion.None)
                            {
                                builder.MidiChannel = 9;
                            }
                            else
                            {
                                builder.MidiChannel = channel;
                                builder.Command     = ChannelCommand.ProgramChange;
                                builder.Data1       = GeneralMidiInstruments[instrument] == Instrument.None ? 0 : (int)GeneralMidiInstruments[instrument];
                                if (GeneralMidiInstruments[instrument] == Instrument.Sitar)
                                {
                                    Controller.print("unknown @ " + jagFile.MusicDataPointer);
                                }
                                builder.Build();
                                t.Insert(e.Time / timeScale, builder.Result);
                            }

                            // Note on
                            builder.Command = ChannelCommand.NoteOn;
                            int freq = BitHelpers.ExtractBits(e.Command, 13, 8);
                            int vel  = BitHelpers.ExtractBits(e.Command, 7, 0);
                            //bool hasVelocity = BitHelpers.ExtractBits(e.Command, 1, 7) == 1;
                            builder.Data1 = GetMidiPitch(freq, 349f);
                            //builder.Data2 = UnityEngine.Mathf.RoundToInt(127f * (vel / 7f));
                            float velf = ((vel + 1) / 128f); // hack
                            int   veli = Mathf.RoundToInt(velf * 127f);

                            /*if (!hasVelocity) {
                             *  veli = 127;
                             * }*/
                            if (PercussionInstruments[instrument] != Percussion.None)
                            {
                                builder.Data1             = (int)PercussionInstruments[instrument];
                                builder.Data2             = PercussionInstruments[instrument] == Percussion.None ? 0 : veli;
                                curNoteOnChannel[channel] = builder.Data1 + 128;
                            }
                            else
                            {
                                builder.Data2             = GeneralMidiInstruments[instrument] == Instrument.None ? 0 : veli;
                                curNoteOnChannel[channel] = builder.Data1;
                            }
                            builder.Build();
                            t.Insert(e.Time / timeScale, builder.Result);
                        }
                        else
                        {
                            builder.Command = ChannelCommand.NoteOff;
                            int note = curNoteOnChannel.TryGetValue(channel, out int val) ? val : 0;
                            if (note >= 128)
                            {
                                builder.MidiChannel = 9;
                                builder.Data1       = note - 128;
                            }
                            else
                            {
                                builder.MidiChannel = channel;
                                builder.Data1       = note;
                            }
                            builder.Data2 = 127;
                            curNoteOnChannel.Remove(channel);

                            builder.Build();
                            t.Insert(e.Time / timeScale, builder.Result);
                        }
                    }
                }
            }
            return(t);
        }
Exemplo n.º 13
0
        private static void CodeFromThread()
        {
            ChannelMessageBuilder channelBuilder = new ChannelMessageBuilder();
            TempoChangeBuilder    tempoBuilder   = new TempoChangeBuilder();
            Sequencer             s = new Sequencer();

            s.Sequence = new Sequence();

            Track track0 = new Track();
            Track track1 = new Track();
            Track track2 = new Track();

            s.Sequence.Add(track0);
            s.Sequence.Add(track1);
            s.Sequence.Add(track2);

            //tempoBuilder.Tempo = (int)(1 / 150.0 * 60000000);
            //tempoBuilder.Build();
            //track0.Insert(0, tempoBuilder.Result);

            channelBuilder.MidiChannel = 1;

            channelBuilder.Command = ChannelCommand.ProgramChange;
            channelBuilder.Data1   = (int)GeneralMidiInstrument.AcousticGrandPiano;
            channelBuilder.Data2   = 0;
            channelBuilder.Build();
            track1.Insert(0, channelBuilder.Result);

            channelBuilder.Command = ChannelCommand.NoteOn;
            channelBuilder.Data1   = 60;  // note C
            channelBuilder.Data2   = 127; // velocity 127
            channelBuilder.Build();
            track1.Insert(0, channelBuilder.Result);

            channelBuilder.Command = ChannelCommand.NoteOff;
            channelBuilder.Data1   = 60; // note C
            channelBuilder.Data2   = 0;  // note off, so velocity 0
            channelBuilder.Build();
            track1.Insert(479, channelBuilder.Result);

            channelBuilder.MidiChannel = 2;

            channelBuilder.Command = ChannelCommand.ProgramChange;
            channelBuilder.Data1   = (int)GeneralMidiInstrument.AcousticBass;
            channelBuilder.Data2   = 0;
            channelBuilder.Build();
            track2.Insert(0, channelBuilder.Result);

            channelBuilder.Command = ChannelCommand.NoteOn;
            channelBuilder.Data1   = 67; // note G
            channelBuilder.Data2   = 60; // velocity 60
            channelBuilder.Build();
            track2.Insert(480, channelBuilder.Result);

            //channelBuilder.Command = ChannelCommand.NoteOff;
            //channelBuilder.Data1 = 67; // note G
            //channelBuilder.Data2 = 0; // note off, so velocity 0
            //channelBuilder.Build();
            //track2.Insert(480 + 760, channelBuilder.Result);

            s.Sequence.Save("test.mid");
            //s.Start();
        }
Exemplo n.º 14
0
        public override void SaveAsMIDI(string fileName)
        {
            if (NumTracks == 0)
            {
                throw new InvalidDataException("This song has no tracks.");
            }

            CalculateTicks();
            var midi = new Sequence(24)
            {
                Format = 1
            };
            var metaTrack = new Sanford.Multimedia.Midi.Track();

            midi.Add(metaTrack);

            for (int i = 0; i < NumTracks; i++)
            {
                var track = new Sanford.Multimedia.Midi.Track();
                midi.Add(track);

                int endOfPattern = 0, startOfPatternTicks = 0, endOfPatternTicks = 0, shift = 0;
                var playing = new List <M4ANoteCommand>();

                for (int j = 0; j < Commands[i].Count; j++)
                {
                    var e     = Commands[i][j];
                    int ticks = e.AbsoluteTicks + (endOfPatternTicks - startOfPatternTicks);

                    switch (e.Command)
                    {
                    case KeyShiftCommand keysh:
                        shift = keysh.Shift;
                        break;

                    case M4ANoteCommand note:
                        int n = (note.Note + shift).Clamp(0, 0x7F);
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.NoteOn, i, n, note.Velocity));
                        if (note.Duration != -1)
                        {
                            track.Insert(ticks + note.Duration, new ChannelMessage(ChannelCommand.NoteOff, i, n));
                        }
                        else
                        {
                            playing.Add(note);
                        }
                        break;

                    case EndOfTieCommand eot:
                        M4ANoteCommand nc = null;

                        if (eot.Note == -1)
                        {
                            nc = playing.LastOrDefault();
                        }
                        else
                        {
                            nc = playing.LastOrDefault(no => no.Note == eot.Note);
                        }

                        if (nc != null)
                        {
                            n = (nc.Note + shift).Clamp(0, 0x7F);
                            track.Insert(ticks, new ChannelMessage(ChannelCommand.NoteOff, i, n));
                            playing.Remove(nc);
                        }
                        break;

                    case PriorityCommand prio:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.VolumeFine, prio.Priority));
                        break;

                    case VoiceCommand voice:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.ProgramChange, i, voice.Voice));
                        break;

                    case VolumeCommand vol:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Volume, vol.Volume));
                        break;

                    case PanpotCommand pan:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Pan, pan.Panpot + 0x40));
                        break;

                    case BendCommand bend:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.PitchWheel, i, 0, bend.Bend + 0x40));
                        break;

                    case BendRangeCommand bendr:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 20, bendr.Range));
                        break;

                    case LFOSpeedCommand lfos:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 21, lfos.Speed));
                        break;

                    case LFODelayCommand lfodl:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 26, lfodl.Delay));
                        break;

                    case ModDepthCommand mod:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.ModulationWheel, mod.Depth));
                        break;

                    case ModTypeCommand modt:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 22, modt.Type));
                        break;

                    case TuneCommand tune:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 24, tune.Tune));
                        break;

                    case LibraryCommand xcmd:
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 30, xcmd.Command));
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 29, xcmd.Argument));
                        break;

                    case TempoCommand tempo:
                        var change = new TempoChangeBuilder {
                            Tempo = (60000000 / tempo.Tempo)
                        };
                        change.Build();
                        metaTrack.Insert(ticks, change.Result);
                        break;

                    case CallCommand patt:
                        int callCmd = Commands[i].FindIndex(c => c.GetOffset() == patt.Offset);
                        endOfPattern      = j;
                        endOfPatternTicks = e.AbsoluteTicks;
                        j = callCmd - 1;     // -1 for incoming ++
                        startOfPatternTicks = Commands[i][j + 1].AbsoluteTicks;
                        break;

                    case ReturnCommand _:
                        if (endOfPattern != 0)
                        {
                            j            = endOfPattern;
                            endOfPattern = startOfPatternTicks = endOfPatternTicks = 0;
                        }
                        break;

                    case GoToCommand goTo:
                        if (i == 0)
                        {
                            int jumpCmd = Commands[i].FindIndex(c => c.GetOffset() == goTo.Offset);
                            metaTrack.Insert(Commands[i][jumpCmd].AbsoluteTicks, new MetaMessage(MetaType.Marker, new byte[] { (byte)'[' }));
                            metaTrack.Insert(ticks, new MetaMessage(MetaType.Marker, new byte[] { (byte)']' }));
                        }
                        break;

                    case FinishCommand _:
                        goto endOfTrack;
                    }
                }

                endOfTrack :;
            }
            midi.Save(fileName);
        }
Exemplo n.º 15
0
        internal void SaveAsMIDI(string fileName)
        {
            if (NumTracks == 0)
            {
                throw new InvalidDataException("This song has no tracks.");
            }
            if (ROM.Instance.Game.Engine.Type != EngineType.M4A)
            {
                throw new PlatformNotSupportedException("Exporting to MIDI from this game engine is not supported at this time.");
            }

            CalculateTicks();
            var midi = new Sequence(Engine.GetTicksPerBar() / 4)
            {
                Format = 2
            };

            for (int i = 0; i < NumTracks; i++)
            {
                var track = new Sanford.Multimedia.Midi.Track();
                midi.Add(track);

                int endOfPattern = 0, startOfPatternTicks = 0, endOfPatternTicks = 0, shift = 0;
                var playing = new List <M4ANoteCommand>();

                for (int j = 0; j < Commands[i].Count; j++)
                {
                    var e     = Commands[i][j];
                    int ticks = (int)(e.AbsoluteTicks + (endOfPatternTicks - startOfPatternTicks));

                    if (e.Command is KeyShiftCommand keysh)
                    {
                        shift = keysh.Shift;
                    }
                    else if (e.Command is M4ANoteCommand note)
                    {
                        int n = (note.Note + shift).Clamp(0, 127);
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.NoteOn, i, n, note.Velocity));
                        if (note.Duration != -1)
                        {
                            track.Insert(ticks + note.Duration, new ChannelMessage(ChannelCommand.NoteOff, i, n));
                        }
                        else
                        {
                            playing.Add(note);
                        }
                    }
                    else if (e.Command is EndOfTieCommand eot)
                    {
                        M4ANoteCommand nc = null;

                        if (eot.Note == -1)
                        {
                            nc = playing.LastOrDefault();
                        }
                        else
                        {
                            nc = playing.LastOrDefault(n => n.Note == eot.Note);
                        }

                        if (nc != null)
                        {
                            int no = (nc.Note + shift).Clamp(0, 127);
                            track.Insert(ticks, new ChannelMessage(ChannelCommand.NoteOff, i, no));
                            playing.Remove(nc);
                        }
                    }
                    else if (e.Command is VoiceCommand voice)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.ProgramChange, i, voice.Voice));
                    }
                    else if (e.Command is VolumeCommand vol)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Volume, vol.Volume));
                    }
                    else if (e.Command is PanpotCommand pan)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.Pan, pan.Panpot + 0x40));
                    }
                    else if (e.Command is BendCommand bend)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.PitchWheel, i, 0, bend.Bend + 0x40));
                    }
                    else if (e.Command is BendRangeCommand bendr)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 20, bendr.Range));
                    }
                    else if (e.Command is LFOSpeedCommand lfos)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 21, lfos.Speed));
                    }
                    else if (e.Command is LFODelayCommand lfodl)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 26, lfodl.Delay));
                    }
                    else if (e.Command is ModDepthCommand mod)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, (int)ControllerType.ModulationWheel, mod.Depth));
                    }
                    else if (e.Command is ModTypeCommand modt)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 22, modt.Type));
                    }
                    else if (e.Command is TuneCommand tune)
                    {
                        track.Insert(ticks, new ChannelMessage(ChannelCommand.Controller, i, 24, tune.Tune));
                    }
                    else if (e.Command is TempoCommand tempo)
                    {
                        var change = new TempoChangeBuilder {
                            Tempo = (60000000 / tempo.Tempo)
                        };
                        change.Build();
                        track.Insert(ticks, change.Result);
                    }
                    else if (e.Command is CallCommand patt)
                    {
                        int callCmd = Commands[i].FindIndex(c => c.Offset == patt.Offset);
                        endOfPattern      = j;
                        endOfPatternTicks = (int)e.AbsoluteTicks;
                        j = callCmd - 1; // -1 for incoming ++
                        startOfPatternTicks = (int)Commands[i][j + 1].AbsoluteTicks;
                    }
                    else if (e.Command is ReturnCommand)
                    {
                        if (endOfPattern != 0)
                        {
                            j            = endOfPattern;
                            endOfPattern = startOfPatternTicks = endOfPatternTicks = 0;
                        }
                    }
                    else if (i == 0 && e.Command is GoToCommand goTo)
                    {
                        track.Insert(ticks, new MetaMessage(MetaType.Marker, new byte[] { (byte)']' }));
                        int jumpCmd = Commands[i].FindIndex(c => c.Offset == goTo.Offset);
                        track.Insert((int)Commands[i][jumpCmd].AbsoluteTicks, new MetaMessage(MetaType.Marker, new byte[] { (byte)'[' }));
                    }
                    else if (e.Command is FinishCommand fine)
                    {
                        track.Insert(ticks, new MetaMessage(MetaType.EndOfTrack, new byte[0]));
                        break;
                    }
                }
            }
            midi.Save(fileName);
        }
Exemplo n.º 16
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);
        }