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 MetaMessage BuildMessage()
        {
            var b = new TempoChangeBuilder();

            b.Tempo = (int)Tempo;
            b.Build();
            return(b.Result);
        }
Exemplo n.º 3
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.º 4
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.º 5
0
        public double outputToMidi(Song output)
        {
            //5 Tracks (Just in case; so far MIDIOut is currently utilizing 2: 1 for instrument and another for notes). Each track added to sequence right after
            Track[] track   = new Track[5];
            double  songLen = 0;

            for (int i = 0; i < 5; i++)
            {
                track[i] = new Track();
                sequence.Add(track[i]);
            }
            //Set the tempo (assuming Song.Tempo is in bpm)
            tempoBuilder.Tempo = (int)(1.0 / output.Tempo * 60000000);
            tempoBuilder.Build();
            track[0].Insert(0, tempoBuilder.Result);
            //Set instrument

            /*builder.Command = ChannelCommand.ProgramChange;
             * //builder.Data1 = (int)GeneralMidiInstrument.AcousticGrandPiano;
             * builder.Data2 = 0;
             * builder.Build();
             * track[1].Insert(0, builder.Result);*/
            //Tick position
            int pos = 0;
            //Note length
            int len = 0;
            //MidiChannel number
            int c = 1;

            //Set MidiChannel number to 1
            builder.MidiChannel = c;
            //Iterate through the chord voice and turn them on; Each iteration will save the note and length values
            int startOfSegment = 0;

            for (int i = 0; i < output.songData.Count; i++)
            {
                startOfSegment = pos;
                for (int j = 0; j < output.songData[i].chordPattern.Count; j++)
                {
                    //Reset channel values to stop outOfBoundsException : Austin
                    c = 1;
                    builder.MidiChannel = c;
                    foreach (var item in (output.songData[i].chordPattern[j].chordVoice))
                    {
                        String note = item.noteValue; //C, C#, D, D#, E, F, F#, G, G#, A, A#
                        len = item.length;            //in 16th notes
                        //Switch note on
                        builder.Command = ChannelCommand.ProgramChange;
                        if (output.Genre == "Generic" || output.Genre == "Jazz")
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.AcousticGrandPiano;
                        }
                        else if (output.Genre == "Classical")
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.Violin;
                        }
                        else if (output.Genre == "4-Chord Pop/Rock")
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.ElectricGuitarMuted;
                        }
                        builder.Data2 = 0;
                        builder.Build();
                        track[1].Insert(pos, builder.Result);
                        builder.Command = ChannelCommand.NoteOn;
                        builder.Data1   = midiValOfNote(note);
                        if (output.Genre == "Generic")
                        {
                            builder.Data2 = 100;
                        }
                        else if (output.Genre == "Classical")
                        {
                            builder.Data2 = 80;
                        }
                        else if (output.Genre == "Jazz")
                        {
                            builder.Data2 = 110;
                        }
                        else if (output.Genre == "4-Chord Pop/Rock")
                        {
                            builder.Data2 = 120;
                        }

                        builder.Build();                      //Build the message
                        track[1].Insert(pos, builder.Result); //Insert into Track 1 at tick position 'pos'
                        //Increment MIDI channel by 1
                        c += 1;
                        builder.MidiChannel = c;
                    }//endforeach

                    /*Tick position increment; This will be based on the last note of the previous chord, but I think it's safe to assume that its length will be the same as the rest of the chord tones of that chord.
                     * PpqnClock.PpqnMinValue is the minimum PPQ value (24) set by the class library PpqnClock.*/
                    songLen            += len / 4;
                    pos                += (PpqnClock.PpqnMinValue / 4 * len);
                    c                   = 1;
                    builder.MidiChannel = c;

                    foreach (var item in (output.songData[i].chordPattern[j].chordVoice))
                    {
                        String note = item.noteValue;
                        len = item.length;
                        //Set Note Off
                        builder.Command = ChannelCommand.NoteOff;
                        builder.Data1   = midiValOfNote(note);
                        builder.Data2   = 0;                  //Set volume to mute
                        builder.Build();                      //Build the message
                        track[1].Insert(pos, builder.Result); //Insert into Track 1 at tick position 'pos'
                        //Increment MIDI channel by 1
                        c += 1;
                        builder.MidiChannel = c;
                        //songLen += item.length / 16;
                    } //endforeach
                }     //endfor

                for (int q = 0; q < output.songData[i].melodies.Count(); q++)
                {
                    pos = startOfSegment;
                    for (int j = 0; j < output.songData[i].melodies[q].melodicLine.Count(); j++)
                    {
                        Song.Note outputNote = output.songData[i].melodies[q].melodicLine[j];
                        String    note       = outputNote.noteValue;
                        int       noteLength = outputNote.length; //in 16th notes
                        //Switch note on
                        builder.Command = ChannelCommand.ProgramChange;
                        if (output.Genre == "Generic")
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.ElectricGuitarJazz;
                        }
                        else if (output.Genre == "Classical")
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.Violin;
                        }
                        else if (output.Genre == "Twelve-tone")
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.AcousticGrandPiano;
                        }
                        else if (output.Genre == "Jazz")
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.AltoSax;
                        }
                        else if (output.Genre == "4-Chord Pop/Rock" && q == 0)
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.ChoirAahs;
                        }
                        else if (output.Genre == "4-Chord Pop/Rock" && q == 1)
                        {
                            builder.Data1 = (int)GeneralMidiInstrument.ElectricBassPick;
                        }
                        builder.Data2 = 0;
                        builder.Build();
                        track[q + 2].Insert(pos, builder.Result);
                        builder.Command = ChannelCommand.NoteOn;
                        builder.Data1   = midiValOfNote(note);
                        builder.Data2   = 127;                    //Set volume to max
                        builder.Build();                          //Build the message
                        track[q + 2].Insert(pos, builder.Result); //Insert into Track 1 at tick position 'pos'
                        //Increment MIDI channel by 1
                        pos += (PpqnClock.PpqnMinValue / 4 * noteLength);
                        //Set Note Off
                        builder.Command = ChannelCommand.NoteOff;
                        builder.Data1   = midiValOfNote(note);
                        builder.Data2   = 0; //Set volume to mute
                        builder.Build();     //Build the message
                        track[q + 2].Insert(pos, builder.Result);
                    }
                }
            }//endfor
             //Submits file to the C:\BlottoBeats Folder where it is stored until another song is generated

            /*if (!Directory.Exists(@"C:\BlottoBeats"))
             * {
             *  Directory.CreateDirectory(@"C:\BlottoBeats");
             *
             * }*/
            if (File.Exists("temp.mid"))
            {
                File.Delete("temp.mid");
            }

            sequence.Save("temp.mid");

            return(((double)pos) / (PpqnClock.PpqnMinValue / 4) / 4 / output.Tempo * 60);

            //Code to play sequence in client. Currently not functioning
            //s.Sequence = sequence;
            //s.Start();
        }
Exemplo n.º 6
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.º 7
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.º 8
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.º 9
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.º 10
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.º 11
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);
        }