public void Process(MetaMessage message)
        {
            #region Require

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

            #endregion

            #region Guard

            if (message.MetaType != MetaType.Tempo)
            {
                if (message.MetaType == MetaType.TimeSignature)
                {
                    var ts = new TimeSignatureBuilder(message);
                    this.ClocksPerMetronomeClick = ts.ClocksPerMetronomeClick;
                }
                return;
            }

            #endregion

            TempoChangeBuilder builder = new TempoChangeBuilder(message);

            // Set the new tempo.
            Tempo = builder.Tempo;
        }
 public static MetaMessage BuildMessage(int numerator = 4, int denominator = 4, int clocksPerMetronomeClick = 24, int thirtySecondNotesPerQuarterNote = 8)
 {
     var sb = new TimeSignatureBuilder();
     sb.Numerator = (byte)numerator;
     sb.Denominator = (byte)denominator;
     sb.ClocksPerMetronomeClick = (byte)clocksPerMetronomeClick;
     sb.ThirtySecondNotesPerQuarterNote = (byte)thirtySecondNotesPerQuarterNote;
     sb.Build();
     return sb.Result;
 }
        public GuitarTimeSignature(GuitarMessageList owner, MidiEvent ev)
            : base(owner, ev, null, GuitarMessageType.GuitarTimeSignature)
        {
            if (ev == null)
            {
                SetDownTick(0);
            }
            else
            {
                SetDownEvent(ev);

                var builder = new TimeSignatureBuilder((MetaMessage)ev.Clone());

                Numerator = builder.Numerator;
                Denominator = builder.Denominator;
                ClocksPerMetronomeClick = builder.ClocksPerMetronomeClick;

                ThirtySecondNotesPerQuarterNote = builder.ThirtySecondNotesPerQuarterNote;
            }
        }
Пример #4
0
 private static IMidiMessage Convert(Event e, Track track)
 {
     if (e is NoteEvent)
     {
         NoteEvent note = (NoteEvent)e;
         if (note.Type == NoteEvent.EventType.NoteOff)
         {
             ChannelMessageBuilder b = new ChannelMessageBuilder();
             b.MidiChannel = note.Channel;
             b.Command = ChannelCommand.NoteOff;
             b.Data1 = ChannelNoteToMidiPitch(note.Pitch);
             b.Data2 = ChannelVelocityToMidiVolume(note.Velocity);
             b.Build();
             return b.Result;
         }
         else
         {
             ChannelMessageBuilder b = new ChannelMessageBuilder();
             b.MidiChannel = note.Channel;
             b.Command = ChannelCommand.NoteOn;
             b.Data1 = ChannelNoteToMidiPitch(note.Pitch);
             b.Data2 = ChannelVelocityToMidiVolume(note.Velocity);
             b.Build();
             return b.Result;
         }
     }
     else if (e is TempoEvent)
     {
         TempoEvent tempoEvent = (TempoEvent)e;
         TempoChangeBuilder builder = new TempoChangeBuilder();
         // convert BPM to microseconds
         builder.Tempo = 60000000 / tempoEvent.TempoBpm;
         builder.Build();
         return builder.Result;
     }
     else if (e is TimeSignatureEvent)
     {
         TimeSignatureEvent timeSignatureEvent = (TimeSignatureEvent)e;
         TimeSignatureBuilder builder = new TimeSignatureBuilder();
         builder.Numerator = (byte)timeSignatureEvent.BeatsPerBar;
         builder.Denominator = (byte)timeSignatureEvent.BeatValue;
         builder.ClocksPerMetronomeClick = 24;
         builder.ThirtySecondNotesPerQuarterNote = 8;
         builder.Build();
         return builder.Result;
     }
     else
     {
         Debug.Fail("unknown event type " + e.GetType().Name);
         return null;
     }
 }
Пример #5
0
        private void importMIDIToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (importDlg.ShowDialog(this)
                == System.Windows.Forms.DialogResult.Cancel)
                return;

            List<PNote> notes = new List<PNote>();
            PNote curNote = PNote.Default;
            float tempo = 1;
            float timeSig = 4f;

            // first, we pull midi data
            Sequence s = new Sequence(importDlg.FileName);

            // quickly see if there's a piano track first
            // and get the tempo as well
            int piano = -1;
            for (int it = 0; it < s.Count; it++)
            {
                Track t = s[it];
                foreach (MidiEvent me in t.Iterator())
                {
                    switch (me.MidiMessage.MessageType)
                    {
                        case MessageType.Channel:
                            {
                                ChannelMessage m = (ChannelMessage)me.MidiMessage;
                                if (m.Command == ChannelCommand.ProgramChange)
                                    if ((GeneralMidiInstrument)m.Data1 == GeneralMidiInstrument.AcousticGrandPiano)
                                    {
                                        piano = it;
                                    }
                            }
                            break;
                        case MessageType.Meta:
                            {
                                MetaMessage m = (MetaMessage)me.MidiMessage;
                                if (m.MetaType == MetaType.Tempo)
                                    tempo = (new TempoChangeBuilder(m)).Tempo;
                                else if (m.MetaType == MetaType.TimeSignature)
                                    timeSig = new TimeSignatureBuilder(m).Denominator;
                            }
                            break;
                    }
                    if (piano >= 0)
                        break;
                }
                if (piano >= 0)
                    break;
            }

            // didn't find one, so just try 0th track anyway
            if (piano == -1)
                piano = 0;

            // now, pull all notes (and tempo)
            // and make sure it's a channel that has content
            for (int it = piano; it < s.Count; it++)
            {
                Track t = s[it];

                int delta = 0;
                foreach (MidiEvent me in t.Iterator())
                {
                    delta += me.DeltaTicks;

                    switch (me.MidiMessage.MessageType)
                    {
                        case MessageType.Channel:
                            {
                                ChannelMessage m = (ChannelMessage)me.MidiMessage;
                                switch (m.Command)
                                {
                                    case ChannelCommand.NoteOn:
                                        if (curNote.Note != "")
                                        {
                                            curNote.Length = delta / 1000F;
                                            delta = 0;
                                            notes.Add(curNote);
                                        }

                                        curNote.Note = note2Piano(m.Data1);
                                        break;
                                }
                            }
                            break;
                        case MessageType.Meta:
                            {
                                MetaMessage m = (MetaMessage)me.MidiMessage;
                                if (m.MetaType == MetaType.Tempo)
                                    tempo = (new TempoChangeBuilder(m)).Tempo;
                            }
                            break;
                    }
                }

                // make sure we get last note
                if (curNote.Note != "")
                {
                    curNote.Length = delta / 1000F;
                    notes.Add(curNote);
                }

                // we found a track with content!
                if (notes.Count > 0)
                    break;
            }

            // compress redundant accidentals/octaves
            char[] notemods = new char[7];
            int[] noteocts = new int[7];
            for (int i = 0; i < 7; i++)
            {
                notemods[i] = 'n';
                noteocts[i] = 3;
            }
            for (int i = 0; i < notes.Count; i++)
            {
                string noteStr = notes[i].Note;
                int cur_note = noteStr[0] - 0x41;
                char mod = noteStr[1];
                int oct = int.Parse(noteStr.Substring(2));

                noteStr = noteStr.Substring(0, 1);
                if (mod != notemods[cur_note])
                {
                    noteStr += new string(mod, 1);
                    notemods[cur_note] = mod;
                }
                if (oct != noteocts[cur_note])
                {
                    noteStr += oct.ToString();
                    noteocts[cur_note] = oct;
                }

                notes[i] = new PNote(notes[i].Length, noteStr);
            }

            // now, we find what the "beat" length should be,
            // by counting numbers of times for each length, and finding statistical mode
            Dictionary<float, int> scores = new Dictionary<float, int>();
            foreach (PNote n in notes)
            {
                if (n.Length != 0)
                    if (scores.Keys.Contains(n.Length))
                        scores[n.Length]++;
                    else
                        scores.Add(n.Length, 1);
            }
            float winner = 1;
            int score = 0;
            foreach (KeyValuePair<float, int> kv in scores)
            {
                if (kv.Value > score)
                {
                    winner = kv.Key;
                    score = kv.Value;
                }
            }
            // realign all of them to match beat length
            for (int i = 0; i < notes.Count; i++)
            {
                notes[i] = new PNote(notes[i].Length / winner, notes[i].Note);
            }

            // compress chords down
            for (int i = 0; i < notes.Count; i++)
            {
                if (notes[i].Length == 0 && i < notes.Count - 1)
                {
                    notes[i + 1] = new PNote(notes[i + 1].Length, notes[i].Note + "-" + notes[i + 1].Note);
                    notes.RemoveAt(i);
                    i--;
                }
            }

            // add in time
            for (int i = 0; i < notes.Count; i++)
            {
                float len = notes[i].Length;
                notes[i] = new PNote(len, notes[i].Note + (len != 1 ? "/" + (1 / len).ToString("0.##") : ""));
            }

            // what is the bpm, anyway?
            int rpm = (int)(28800000 / tempo / winner); // 60 * 1,000,000 * .48  the .48 is because note lengths for some reason midi makes the beat note be .48 long

            // now, output!
            string line = "";
            string output = "";
            int lineCount = 1;
            foreach (PNote n in notes)
            {
                if (line.Length + n.Note.Length + 1 > 51)
                {
                    output += line.Substring(0, line.Length - 1) + "\r\n";
                    line = "";
                    if (lineCount == 50)
                        break;
                    lineCount++;
                }
                line += n.Note + ",";
            }
            if (line.Length > 0)
                output += line.Substring(0, line.Length - 1);
            OutputTxt.Text = "BPM: " + rpm.ToString() + "\r\n" + output;
            OutputTxt.SelectAll();
        }
        public List<float> TicksPerQuarter(GeneralMidiInstrument inst, bool throwExceptionIfNotFound = false)
        {
            var messages = this.GetOrderedMessages(inst, throwExceptionIfNotFound);
            var meta = messages
                .Where(x => x.MidiMessage is MetaMessage)
                .Select(x => x.MidiMessage as MetaMessage)
                .Where(x => x.MetaType == MetaType.TimeSignature);

            var time = new TimeSignatureBuilder();

            return null;
        }
        public void Process(MetaMessage message)
        {
            #region Require

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

            #endregion

            #region Guard

            if (message.MetaType != MetaType.Tempo)
            {
                if (message.MetaType == MetaType.TimeSignature)
                {
                    var ts = new TimeSignatureBuilder(message);
                    this.ClocksPerMetronomeClick = ts.ClocksPerMetronomeClick;
                }
                return;
            }

            #endregion

            TempoChangeBuilder builder = new TempoChangeBuilder(message);

            // Set the new tempo.
            Tempo = builder.Tempo;
        }
Пример #8
0
        static void Main(string[] args)
        {
            bool outputMidiVelocity = false;

            //var filename = "01-v-drac.s3m";
            //S3MFile f = S3MFile.Parse(filename);
            //var tempo = 60000000 / (f.Header.InitialTempo);
            //byte numerator = 4;
            //byte denominator = 4;
            //var speed = 3;
            //var skip = 0;

            var filename = "02-v-bewm.s3m";
            S3MFile f = S3MFile.Parse(filename);
            var tempo = 60000000 / (f.Header.InitialTempo);
            byte numerator = 4;
            byte denominator = 4;
            var speed = 3;
            var skip = 0;
            outputMidiVelocity = true;

            /*
            var filename = "V-OPTION.S3M";
            S3MFile f = S3MFile.Parse(filename);
            var tempo = 60000000 / (f.Header.InitialTempo);
            byte numerator = 6;
            byte denominator = 8;
            var speed = 3;
            var skip = 4;
              */
            /*
            var filename = "V-FALCON.S3M";
            S3MFile f = S3MFile.Parse(filename);
            var tempo = 60000000 / (1 * f.Header.InitialTempo);
            byte numerator = 4;
            byte denominator = 4;
            var speed = 3;
            var skip = 0;
            */
            /*
            var filename = "V-CONTRA.IT";
            S3MFile f = S3MFile.Parse(filename);
            var tempo = 60000000 / (1 * f.Header.InitialTempo);
            byte numerator = 4;
            byte denominator = 4;
            var speed = 3;
            var skip = 0;
             * */

            /*
            var filename = "V-BLAST.S3M";
            S3MFile f = S3MFile.Parse(filename);
            var tempo = 60000000 / (1 * f.Header.InitialTempo);
            byte numerator = 4;
            byte denominator = 4;
            var speed = 3;
            var skip = 0;*/

            Sequence s = new Sequence();
            Track t1 = new Track();
            Track t2 = new Track();
            Track t3 = new Track();
            Track drums = new Track();
            Track kick = new Track();
            Track timeTrack = new Track();
            s.Add(timeTrack);
            s.Add(t1);
            s.Add(t2);
            s.Add(t3);
            //s.Add(drums);
            //s.Add(kick);

            var drumPC = new ChannelMessageBuilder();
            drumPC.MidiChannel = 09;
            drumPC.Command = ChannelCommand.ProgramChange;
            drumPC.Data1 = 0;// 79 + ce.Instrument;
            drumPC.Build();
            drums.Insert(0, drumPC.Result);

            kick.Insert(0, drumPC.Result);

            TimeSignatureBuilder tsb = new TimeSignatureBuilder();
            tsb.Numerator = numerator;
            tsb.Denominator = denominator;
            tsb.ClocksPerMetronomeClick = 24;
            tsb.ThirtySecondNotesPerQuarterNote = 8;

            tsb.Build();

            timeTrack.Insert(0, tsb.Result);

            TempoChangeBuilder tcb = new TempoChangeBuilder();
            tcb.Tempo = tempo;
            tcb.Build();

            timeTrack.Insert(0, tcb.Result);

            var outputPatterns = new int[] { 5, 6, 7};

            //var c1 = (from p in f.OrderedPatterns
            //          where patterns.Contains(p.PatternNumber)
            //          select p)
            //         .SelectMany(p => p.Channels)
            //         .Where(c => c.ChannelNumber == 1)
            //         .SelectMany(ce => ce.ChannelEvents);

            //var c2 = (from p in f.OrderedPatterns
            //          where patterns.Contains(p.PatternNumber)
            //          select p)
            //         .SelectMany(p => p.Channels)
            //         .Where(c => c.ChannelNumber == 2)
            //         .SelectMany(ce => ce.ChannelEvents);

            //var c3 = (from p in f.OrderedPatterns
            //          where patterns.Contains(p.PatternNumber)
            //          select p)
            //         .SelectMany(p => p.Channels)
            //         .Where(c => c.ChannelNumber == 3)
            //         .SelectMany(ce => ce.ChannelEvents);

            var patterns = from p in f.OrderedPatterns.Skip(skip) /*where outputPatterns.Contains(p.PatternNumber) */select p;
            //.SelectMany(p => p.Rows);

            Dictionary<int, TrackInfo> tracks = new Dictionary<int, TrackInfo>();
            tracks.Add(1, new TrackInfo(t1));
            tracks[1].Channel = 0;
            tracks.Add(2, new TrackInfo(t2));
            tracks[2].Channel = 1;
            tracks.Add(3, new TrackInfo(t3));
            tracks[3].Channel = 2;
            var di = new TrackInfo(drums);
            di.Channel = 9;
            var mapper = new Func<ChannelEvent, int>(ce =>
            {
                switch (ce.Instrument)
                {
                    case 6:
                        return 42;
                    case 8:
                        return 35;
                    case 9:
                        return 38;
                    case 10:
                        return 47;
                    default:
                        Debug.Fail(ce.Instrument.ToString());
                        return 0;

                }
            });
            di.NoteMapper = mapper;
            var kickInfo = new TrackInfo(kick);
            kickInfo.Channel = 9;
            kickInfo.NoteMapper = mapper;
            tracks.Add(4, di);
            tracks.Add(5, kickInfo);

            var tick = 0;
            foreach (var pattern in patterns)
            {
                bool breakPattern = false;
                foreach (var row in pattern.Rows)
                {
                    //if ((row.RowNumber-1) % 16 == 0)
                    //{
                    //    drums.Insert(tick, kickOn);
                    //    drums.Insert(tick + speed, kickOff);
                    //}
                    foreach (var ce in row.ChannelEvents)
                    {
                        if (ce == null)
                        {
                            //Console.Out.WriteLine("skip");
                            continue;
                        }

                        if (ce.Command == 3)
                        {
                            var modulo = row.RowNumber % 32;
                            if (modulo != 0)
                            {
                                // sad to say, not sure why mod 8 but divide by 16 works
                                var m8 = row.RowNumber % 8;
                                if (m8 == 0)
                                {
                                    var restore = tsb.Result;
                                    tsb.Numerator = (byte)(row.RowNumber / 16);
                                    tsb.Build();
                                    var change = tsb.Result;
                                    timeTrack.Insert(tick, change);
                                    timeTrack.Insert(tick + 3, restore);
                                }

                            }
                            //Debugger.Break();
                            // pattern break
                            // figure out the time signature of the pattern up to this point
                            // then go back and insert a time signature change message at the beginning
                            // of the pattern
                            // and another one at the end to revert
                            //var restore = tsb.Result;
                            //tsb.Numerator = 2;
                            //tsb.Build();
                            //var change = tsb.Result;
                            //timeTrack.Insert(rowStartTick, change);
                            //timeTrack.Insert(tick + 3, restore);
                            breakPattern = true;
                        }

                        if (!tracks.ContainsKey(ce.ChannelNumber)) continue;
                        TrackInfo ti = tracks[ce.ChannelNumber];

                        if (ce.Note == -1 )
                        {
                            // skip
                        }
                        else if( ce.Note == 0xFF)
                        {
                            // re-use current note, but change instrument

                            //Console.Out.WriteLine("skip");
                        }
                        else if (ce.Note == 0xFE) //off
                        {
                            if (ti.LastPitch != -1)
                            {
                                NoteOff(tick, ti);
                            }
                        }
                        else
                        {
                            //if (ce.Volume != -1 && ce.Volume < 32) continue;
                            if (ti.LastPitch != -1)
                            {
                                NoteOff(tick, ti);
                            }

                            //p = ProgramChange(ti.Track, tick, p, ce);

                            var delay = 0;
                            if (ce.Command == 19)
                            {
                                if (208 <= ce.Data && ce.Data <= 214)  // HACK: 214 is a guess at the top range of SD commands
                                {
                                    delay = ce.Data - 208;
                                    Debug.Assert(delay >= 0);
                                }
                            }

                            NoteOn(tick + delay, ti, ce);

                        }

                    }
                    tick += speed;
                    if (breakPattern)
                    {
                        break;
                    }
                }
            }

            foreach (var pair in tracks)
            {
                if (pair.Value.LastPitch != -1)
                {
                    NoteOff(tick, pair.Value);
                }
            }

            foreach (MidiEvent m in drums.Iterator().Take(5))
            {
                if (m.MidiMessage is ChannelMessage)
                {
                    ChannelMessage cm = (ChannelMessage)m.MidiMessage;
                    Console.Out.WriteLine("{0} {1}", m.AbsoluteTicks, cm.Command);
                }
            }

            s.Save(Path.ChangeExtension(filename, ".mid"));
            /*
            var tick = 0;
            var speed = 3;
            var lastNote = -1;
            var p = -1;
            foreach (var ce in c1)
            {
                if (ce == null || ce.Note == -1 || ce.Note == 0xFF)
                {
                    tick += speed;
                    Console.Out.WriteLine("skip");
                    continue;
                }
                else if (ce.Note == 0xFE) //off
                {
                    lastNote = NoteOff(t, tick, lastNote);
                }
                else
                {
                    if (lastNote != -1)
                    {
                        lastNote = NoteOff(t, tick, lastNote);
                    }

                    p = ProgramChange(t, tick, p, ce);

                    var delay = 0;
                    if (ce.Command == 19)
                    {
                        if (208 <= ce.Data && ce.Data <= 214)  // HACK: 214 is a guess at the top range of SD commands
                        {
                            delay = ce.Data - 208;
                            Debug.Assert(delay >= 0);
                        }
                    }

                    lastNote = NoteOn(t, tick + delay, ce.Note);

                }
                tick += speed;
            }
            lastNote = NoteOff(t, tick, lastNote);
             *
             * */
        }