Exemplo n.º 1
0
 static void SimpleStreamingDemo()
 {
     // just grab the first output stream
     using (var stm = MidiDevice.Streams[0])
     {
         // open it
         stm.Open();
         // read a MIDI file
         var mf = MidiFile
                                                               //.ReadFrom(@"..\..\Feel_good_4beatsBass.mid");
                  .ReadFrom(@"..\..\Bohemian-Rhapsody-1.mid"); // > 64kb!
         //.ReadFrom(@"..\..\A-Warm-Place.mid");
         // merge the tracks for playback
         var seq = MidiSequence.Merge(mf.Tracks);
         // set the stream timebase
         stm.TimeBase = mf.TimeBase;
         // start the playback
         stm.Start();
         Console.Error.WriteLine("Press any key to exit...");
         // if we weren't looping
         // we wouldn't need to
         // hook this:
         stm.SendComplete += delegate(object s, EventArgs e)
         {
             // loop
             stm.Send(seq.Events);
         };
         // kick things off
         stm.Send(seq.Events);
         // wait for exit
         Console.ReadKey();
     }
 }
Exemplo n.º 2
0
        static void TestPlaybackTiming()
        {
            var mf  = MidiFile.ReadFrom(@"..\..\GORILLAZ_-_Feel_Good_Inc.mid");
            var seq = MidiSequence.Merge(mf.Tracks);

            Console.WriteLine(mf.Duration);
            var st = _PreciseUtcNowTicks;
            var et = 0L;

            using (var stm = MidiDevice.Streams[0])
            {
                stm.SendComplete += delegate(object s, EventArgs ea)
                {
                    Interlocked.Exchange(ref et, _PreciseUtcNowTicks);
                };
                stm.Open();
                stm.TimeBase = mf.TimeBase;
                stm.Start();
                stm.Send(seq.Events);
                while (0 == et)
                {
                    Thread.Sleep(1);
                }
            }

            Console.WriteLine(new TimeSpan(et - st));
        }
Exemplo n.º 3
0
 public Main()
 {
     MinimumSize = new Size(200, 130);
     InitializeComponent();
     MidiInputComboBox.DisplayMember  = "Name";
     MidiOutputComboBox.DisplayMember = "Name";
     _RefreshDeviceList();
     Visualizer.Sequence = MidiSequence.Merge(MidiFile.ReadFrom(@"..\..\GORILLAZ_-_Feel_Good_Inc.mid").Tracks);
 }
Exemplo n.º 4
0
        static void SimpleStreamingDemo()
        {
            // just grab the first output stream
            using (var stm = MidiDevice.Streams[0])
            {
                // open it
                stm.Open();
                // read a MIDI file
                var midiFile = MidiFile
                               //.ReadFrom(@"..\..\Feel_good_4beatsBass.mid");
                               //.ReadFrom(@"..\..\Bohemian-Rhapsody-1.mid"); // > 64kb!
                               .ReadFrom(@"..\..\A-Warm-Place.mid");
                //.ReadFrom(@"..\..\50_cent_-_In_Da_Club.mid");
                //.ReadFrom(@"..\..\Beethoven-Moonlight-Sonata.mid");
                //.ReadFrom(@"..\..\Peter-Gunn-1.mid");
                //.ReadFrom(@"..\..\THE BEASTIE BOYS.Sabotage.mid");
                Console.WriteLine(Path.GetFileName(midiFile.FilePath) + " @ " + midiFile.TimeBase + " PQN");
                var tsig = midiFile.TimeSignature;
                Console.WriteLine("Tempo: " + midiFile.Tempo + " BPM @ " + tsig.Numerator + "/" + tsig.Denominator + " time");
                Console.WriteLine("Tracks:");
                for (var i = 0; i < midiFile.Tracks.Count; ++i)
                {
                    var track = midiFile.Tracks[i];
                    Console.Write("\t");
                    var name = track.Name;
                    if (string.IsNullOrEmpty(name))
                    {
                        name = "Track " + i;
                    }
                    Console.WriteLine(name + " \tEvents: " + track.Events.Count);
                }
                Console.WriteLine();
                // merge the tracks for playback
                var seq = MidiSequence.Merge(midiFile.Tracks);
                // set the stream timebase
                stm.TimeBase = midiFile.TimeBase;
                // start the playback
                stm.Start();
                Console.Error.WriteLine("Press any key to exit...");
                // if we weren't looping
                // we wouldn't need to
                // hook this:
                stm.SendComplete += delegate(object s, EventArgs e)
                {
                    // loop
                    stm.Send(seq.Events);
                };
                // kick things off
                stm.Send(seq.Events);

                // wait for exit
                Console.ReadKey();
            }
        }
Exemplo n.º 5
0
        private void _UpdateMidiFile()
        {
            MidiFile file;

            try { file = MidiFile.ReadFrom(FileTextBox.Text); }
            catch { file = null; }
            if (null == file)
            {
                PlayButton.Enabled    = false;
                FileTextBox.ForeColor = Color.Red;
                Visualizer.Sequence   = null;
                return;
            }
            PlayButton.Enabled    = true;
            FileTextBox.ForeColor = SystemColors.WindowText;
            var seq = MidiSequence.Merge(file.Tracks);

            Visualizer.Sequence = seq;
            Visualizer.Width    = seq.Length;
        }
Exemplo n.º 6
0
        private void SaveAsButton_Click(object sender, EventArgs e)
        {
            var res = SaveMidiFile.ShowDialog(this);

            if (DialogResult.OK == res)
            {
                var f = _file;
                if (ResampleUpDown.Value != _file.TimeBase)
                {
                    f = f.Resample(unchecked ((short)ResampleUpDown.Value));
                }
                var trks = new List <MidiSequence>(f.Tracks.Count);
                for (int ic = TrackList.Items.Count, i = 0; i < ic; ++i)
                {
                    if (TrackList.CheckedItems.Contains(TrackList.Items[i]))
                    {
                        trks.Add(f.Tracks[i]);
                    }
                }

                var mf = new MidiFile(1, f.TimeBase);
                if (!MergeTracksCheckBox.Checked)
                {
                    foreach (var tr in trks)
                    {
                        mf.Tracks.Add(_ProcessTrack(tr));
                    }
                }
                else
                {
                    mf.Tracks.Add(_ProcessTrack(MidiSequence.Merge(trks)));
                }
                using (var stm = File.OpenWrite(SaveMidiFile.FileName))
                {
                    mf.WriteTo(stm);
                }
            }
        }
Exemplo n.º 7
0
        void _UpdateMidiFile()
        {
            var exists = false;

            try
            {
                if (File.Exists(MidiFileBox.Text))
                {
                    exists = true;
                }
            }
            catch { }
            TrackList.Items.Clear();
            if (!exists)
            {
                TracksLabel.Text      = "";
                MidiFileBox.ForeColor = Color.Red;
                _file                           = null;
                TrackList.Enabled               = false;
                PreviewButton.Enabled           = false;
                UnitsCombo.Enabled              = false;
                StartCombo.Enabled              = false;
                OffsetUpDown.Enabled            = false;
                LengthUpDown.Enabled            = false;
                StretchUpDown.Enabled           = false;
                MergeTracksCheckBox.Enabled     = false;
                CopyTimingPatchCheckBox.Enabled = false;
                AdjustTempoCheckBox.Enabled     = false;
                ResampleUpDown.Enabled          = false;
                NormalizeCheckBox.Enabled       = false;
                LevelsUpDown.Enabled            = false;
                TransposeUpDown.Enabled         = false;
                WrapCheckBox.Enabled            = false;
                DrumsCheckBox.Enabled           = false;
                SaveAsButton.Enabled            = false;
                TempoUpDown.Enabled             = false;
                Visualizer.Sequence             = null;
                Visualizer.Size                 = VisualizerPanel.Size;
            }
            else
            {
                MidiFileBox.ForeColor = SystemColors.WindowText;
                using (Stream stm = File.OpenRead(MidiFileBox.Text))
                    _file = MidiFile.ReadFrom(stm);
                var i = 0;
                foreach (var trk in _file.Tracks)
                {
                    var s = trk.Name;
                    if (string.IsNullOrEmpty(s))
                    {
                        s = "Track #" + i.ToString();
                    }
                    TrackList.Items.Add(s, true);
                    ++i;
                }
                var sig = _file.TimeSignature;
                var key = _file.KeySignature;
                TracksLabel.Text                = string.Format(_tracksLabelFormat, sig.Numerator, sig.Denominator, key);
                TrackList.Enabled               = true;
                PreviewButton.Enabled           = true;
                UnitsCombo.Enabled              = true;
                StartCombo.Enabled              = true;
                OffsetUpDown.Enabled            = true;
                LengthUpDown.Enabled            = true;
                StretchUpDown.Enabled           = true;
                MergeTracksCheckBox.Enabled     = true;
                CopyTimingPatchCheckBox.Enabled = true;
                AdjustTempoCheckBox.Enabled     = true;
                ResampleUpDown.Enabled          = true;
                NormalizeCheckBox.Enabled       = true;
                LevelsUpDown.Enabled            = true;
                TransposeUpDown.Enabled         = true;
                WrapCheckBox.Enabled            = true;
                DrumsCheckBox.Enabled           = true;
                SaveAsButton.Enabled            = true;
                TempoUpDown.Enabled             = true;

                StretchUpDown.Value             = 1;
                UnitsCombo.SelectedIndex        = 0;
                StartCombo.SelectedIndex        = 0;
                ResampleUpDown.Value            = _file.TimeBase;
                UnitsCombo.SelectedIndex        = 0;
                LengthUpDown.Maximum            = _file.Length / (decimal)_file.TimeBase;
                OffsetUpDown.Maximum            = LengthUpDown.Maximum - 1;
                LengthUpDown.Value              = LengthUpDown.Maximum;
                OffsetUpDown.Value              = 0;
                AdjustTempoCheckBox.Checked     = false;
                MergeTracksCheckBox.Checked     = false;
                NormalizeCheckBox.Checked       = false;
                CopyTimingPatchCheckBox.Checked = true;
                LevelsUpDown.Value              = 1;
                TransposeUpDown.Value           = 0;
                WrapCheckBox.Checked            = false;
                DrumsCheckBox.Checked           = false;
                TempoUpDown.Value   = (decimal)_file.Tempo;
                _dirty              = true;
                _processedFile      = null;
                Visualizer.Sequence = MidiSequence.Merge(_file.Tracks);
                Visualizer.Width    = Math.Max(VisualizerPanel.Width, Visualizer.Sequence.Length / 4);
            }
        }
Exemplo n.º 8
0
        MidiFile _ProcessFile()
        {
            // first we clone the file to be safe
            // that way in case there's no modifications
            // specified in the UI we'll still return
            // a copy.
            var result = _file.Clone();

            // transpose it if specified
            if (0 != TransposeUpDown.Value)
            {
                result = result.Transpose((sbyte)TransposeUpDown.Value, WrapCheckBox.Checked, !DrumsCheckBox.Checked);
            }
            // resample if specified
            if (ResampleUpDown.Value != _file.TimeBase)
            {
                result = result.Resample(unchecked ((short)ResampleUpDown.Value));
            }
            // compute our offset and length in ticks or beats/quarter-notes
            var ofs = OffsetUpDown.Value;
            var len = LengthUpDown.Value;

            if (0 == UnitsCombo.SelectedIndex)             // beats
            {
                len = Math.Min(len * _file.TimeBase, _file.Length);
                ofs = Math.Min(ofs * _file.TimeBase, _file.Length);
            }
            switch (StartCombo.SelectedIndex)
            {
            case 1:
                ofs += result.FirstDownBeat;
                break;

            case 2:
                ofs += result.FirstNoteOn;
                break;
            }
            // nseq holds our patch and timing info
            var nseq = new MidiSequence();

            if (0 != ofs && CopyTimingPatchCheckBox.Checked)
            {
                // we only want to scan until the
                // first note on
                // we need to check all tracks so
                // we merge them into mtrk and scan
                // that
                var mtrk = MidiSequence.Merge(result.Tracks);
                var end  = mtrk.FirstNoteOn;
                if (0 == end)                 // break later:
                {
                    end = mtrk.Length;
                }
                var ins = 0;
                for (int ic = mtrk.Events.Count, i = 0; i < ic; ++i)
                {
                    var ev = mtrk.Events[i];
                    if (ev.Position >= end)
                    {
                        break;
                    }
                    var m = ev.Message;
                    switch (m.Status)
                    {
                    // the reason we don't check for MidiMessageMetaTempo
                    // is a user might have specified MidiMessageMeta for
                    // it instead. we want to handle both
                    case 0xFF:
                        var mm = m as MidiMessageMeta;
                        switch (mm.Data1)
                        {
                        case 0x51:                                         // tempo
                        case 0x54:                                         // smpte
                            if (0 == nseq.Events.Count)
                            {
                                nseq.Events.Add(new MidiEvent(0, ev.Message.Clone()));
                            }
                            else
                            {
                                nseq.Events.Insert(ins, new MidiEvent(0, ev.Message.Clone()));
                            }
                            ++ins;
                            break;
                        }
                        break;

                    default:
                        // check if it's a patch change
                        if (0xC0 == (ev.Message.Status & 0xF0))
                        {
                            if (0 == nseq.Events.Count)
                            {
                                nseq.Events.Add(new MidiEvent(0, ev.Message.Clone()));
                            }
                            else
                            {
                                nseq.Events.Insert(ins, new MidiEvent(0, ev.Message.Clone()));
                            }
                            // increment the insert count
                            ++ins;
                        }
                        break;
                    }
                }
                // set the track to the loop length
                nseq.Events.Add(new MidiEvent((int)len, new MidiMessageMetaEndOfTrack()));
            }
            // see if track 0 is checked
            var hasTrack0 = TrackList.GetItemChecked(0);

            // slice our loop out of it
            if (0 != ofs || result.Length != len)
            {
                result = result.GetRange((int)ofs, (int)len, CopyTimingPatchCheckBox.Checked, false);
            }
            // normalize it!
            if (NormalizeCheckBox.Checked)
            {
                result = result.NormalizeVelocities();
            }
            // scale levels
            if (1m != LevelsUpDown.Value)
            {
                result = result.ScaleVelocities((double)LevelsUpDown.Value);
            }

            // create a temporary copy of our
            // track list
            var l = new List <MidiSequence>(result.Tracks);

            // now clear the result
            result.Tracks.Clear();
            for (int ic = l.Count, i = 0; i < ic; ++i)
            {
                // if the track is checked in the list
                // add it back to result
                if (TrackList.GetItemChecked(i))
                {
                    result.Tracks.Add(l[i]);
                }
            }
            if (0 < nseq.Events.Count)
            {
                // if we don't have track zero we insert
                // one.
                if (!hasTrack0)
                {
                    result.Tracks.Insert(0, nseq);
                }
                else
                {
                    // otherwise we merge with track 0
                    result.Tracks[0] = MidiSequence.Merge(nseq, result.Tracks[0]);
                }
            }
            // next adjust the tempo
            if (_file.Tempo != (double)TempoUpDown.Value)
            {
                result = result.AdjustTempo((double)TempoUpDown.Value);
            }
            // stretch the result. we do this
            // here so the track lengths are
            // correct and we don't need ofs
            // or len anymore
            if (1m != StretchUpDown.Value)
            {
                result = result.Stretch((double)StretchUpDown.Value, AdjustTempoCheckBox.Checked);
            }

            // if merge is checked merge the
            // tracks
            if (MergeTracksCheckBox.Checked)
            {
                var trk = MidiSequence.Merge(result.Tracks);
                result.Tracks.Clear();
                result.Tracks.Add(trk);
            }
            _dirty       = false;
            _reseekDirty = false;
            return(result);
        }
Exemplo n.º 9
0
        private void PreviewButton_Click(object sender, EventArgs e)
        {
            if ("Stop" == PreviewButton.Text)
            {
                if (null != _play)
                {
                    _play.Close();
                }
                MidiFileBox.Enabled    = true;
                BrowseButton.Enabled   = true;
                OutputComboBox.Enabled = true;
                PreviewButton.Text     = "Preview";
                return;
            }

            if (null != _play)
            {
                _play.Close();
            }
            MidiFileBox.Enabled    = false;
            BrowseButton.Enabled   = false;
            OutputComboBox.Enabled = false;
            PreviewButton.Text     = "Stop";
            if (_dirty)
            {
                _processedFile = _ProcessFile();
            }
            var mf = _processedFile;

            _play = (OutputComboBox.SelectedItem as MidiOutputDevice).Stream;
            var stm = _play;
            // we use 100 events, which should be safe and allow
            // for some measure of SYSEX messages in the stream
            // without bypassing the 64kb limit
            const int MAX_EVENT_COUNT = 100;
            const int RATE_TICKS      = 500;
            // our current cursor pos
            var pos = 0;
            // for tracking deltas
            var ofs = 0;
            // for tracking the song position
            var songPos = 0;
            // merge our file for playback
            var seq    = MidiSequence.Merge(mf.Tracks);
            var events = seq.Events;
            // the number of events in the seq
            var len = events.Count;
            // stores the next set of events
            var eventList = new List <MidiEvent>(MAX_EVENT_COUNT);

            // open the stream
            stm.Open();
            // start it
            stm.Start();

            // first set the timebase
            stm.TimeBase = mf.TimeBase;
            // set up our send complete handler
            stm.SendComplete += delegate(object s, EventArgs ea)
            {
                try
                {
                    BeginInvoke(new Action(delegate()
                    {
                        // clear the list
                        eventList.Clear();
                        mf = _processedFile;
                        if (_dirty)
                        {
                            if (_reseekDirty)
                            {
                                var time       = _processedFile.Tracks[0].GetContext(songPos, _processedFile.TimeBase).Time;
                                _processedFile = _ProcessFile();
                                songPos        = _processedFile.Tracks[0].GetPositionAtTime(time, _processedFile.TimeBase);
                                mf             = _processedFile;
                                seq            = MidiSequence.Merge(mf.Tracks);
                                events         = new List <MidiEvent>(seq.GetNextEventsAtPosition(songPos, true));
                                len            = events.Count;
                                pos            = 0;
                            }
                            else
                            {
                                _processedFile = _ProcessFile();
                                mf             = _processedFile;
                                seq            = MidiSequence.Merge(mf.Tracks);
                                events         = seq.Events;
                            }
                            Visualizer.Sequence = seq;
                            Visualizer.Width    = Math.Max(VisualizerPanel.Width, Visualizer.Sequence.Length / 4);
                        }


                        ofs = 0;
                        len = events.Count;
                        // iterate through the next events
                        var next = pos + MAX_EVENT_COUNT;
                        for (; pos < next && ofs <= RATE_TICKS; ++pos)

                        {
                            // if it's past the end, loop it
                            if (len <= pos)
                            {
                                pos     = 0;
                                songPos = 0;
                                events  = seq.Events;
                                break;
                            }
                            var ev   = events[pos];
                            ofs     += ev.Position;
                            songPos += pos;
                            if (ev.Position < RATE_TICKS && RATE_TICKS < ofs)
                            {
                                break;
                            }
                            // otherwise add the next event
                            eventList.Add(ev);
                        }
                        // send the list of events
                        if (MidiStreamState.Closed != stm.State && 0 != eventList.Count)
                        {
                            stm.SendDirect(eventList);
                        }
                    }));
                }
                catch { }
            };
            // add the first events
            for (pos = 0; pos < MAX_EVENT_COUNT && ofs <= RATE_TICKS; ++pos)
            {
                // if it's past the end, loop it
                if (len <= pos)
                {
                    pos     = 0;
                    songPos = 0;
                    events  = seq.Events;
                    break;
                }
                var ev = events[pos];
                ofs += ev.Position;
                if (ev.Position < RATE_TICKS && RATE_TICKS < ofs)
                {
                    break;
                }
                // otherwise add the next event
                eventList.Add(ev);
            }
            // send the list of events
            if (0 != eventList.Count)
            {
                stm.SendDirect(eventList);
            }
        }
Exemplo n.º 10
0
        static void ComplexRecordingDemo()
        {
            using (var idev = MidiDevice.Inputs[0])
            {
                // TODO: currently this doesn't let you
                // change the tempo in the middle of recording

                // match these two variables to your input rate
                short timeBase   = 480;
                var   microTempo = MidiUtility.TempoToMicroTempo(120);

                // track 0 - meta track for tempo info
                var tr0 = new MidiSequence();
                // our seq for recording
                var seq = new MidiSequence();
                // compute our timing based on current microTempo and timeBase
                var ticksusec    = microTempo / (double)timeBase;
                var tickspertick = ticksusec / (TimeSpan.TicksPerMillisecond / 1000) * 100;
                var pos          = 0;
                // set this to _PreciseUtcNowTicks in order
                // to start recording now. Otherwise it will
                // not record until the first message is
                // recieved:
                var startTicks = 0L;

                using (var odev = MidiDevice.Outputs[0])
                {
                    // hook up the delegate
                    idev.Input += delegate(object s, MidiInputEventArgs ea)
                    {
                        // initialize start ticks with the current time in ticks
                        if (0 == startTicks)
                        {
                            startTicks = _PreciseUtcNowTicks;
                        }
                        // compute our current MIDI ticks
                        var midiTicks = (int)Math.Round((_PreciseUtcNowTicks - startTicks) / tickspertick);
                        // pass through to play
                        odev.Send(ea.Message);
                        // HACK: technically the sequence isn't threadsafe but as long as this event
                        // is not reentrant and the MidiSequence isn't touched outside this it should
                        // be fine
                        seq.Events.Add(new MidiEvent(midiTicks - pos, ea.Message));
                        // this is to track our old position
                        // so we can compute deltas
                        pos = midiTicks;
                    };
                    // open the input device
                    idev.Open();
                    // open the output device
                    odev.Open();
                    // add our tempo to the beginning of track 0
                    tr0.Events.Add(new MidiEvent(0, new MidiMessageMetaTempo(microTempo)));
                    // start listening
                    idev.Start();
                    Console.Error.WriteLine("Recording started.");
                    // wait
                    Console.Error.WriteLine("Press any key to stop recording...");
                    Console.ReadKey();
                    // stop the buffer and flush any pending events
                    idev.Stop();
                    idev.Reset();
                }

                // create termination track
                var endTrack = new MidiSequence();
                var len      = seq.Length;
                // comment the following to terminate
                // without the trailing empty score:
                len = unchecked ((int)((_PreciseUtcNowTicks - startTicks) / tickspertick));
                endTrack.Events.Add(new MidiEvent(len, new MidiMessageMetaEndOfTrack()));

                // terminate the tracks
                tr0 = MidiSequence.Merge(tr0, endTrack);
                seq = MidiSequence.Merge(seq, endTrack);

                // build a type 1 midi file
                var mf = new MidiFile(1, timeBase);
                // add both tracks
                mf.Tracks.Add(tr0);
                mf.Tracks.Add(seq);

                // now stream the file to the output
                // just grab the first output stream
                using (var stm = MidiDevice.Streams[0])
                {
                    // open it
                    stm.Open();
                    // merge the tracks for playback
                    seq = MidiSequence.Merge(mf.Tracks);
                    // set the stream timebase
                    stm.TimeBase = mf.TimeBase;
                    // start the playback
                    stm.Start();
                    Console.Error.WriteLine("Press any key to exit...");
                    // if we weren't looping
                    // we wouldn't need to
                    // hook this:
                    stm.SendComplete += delegate(object s, EventArgs e)
                    {
                        // loop
                        stm.Send(seq.Events);
                    };
                    // kick things off
                    stm.Send(seq.Events);
                    // wait for exit
                    Console.ReadKey();
                }
            }
        }
Exemplo n.º 11
0
        static void SimpleRecordingDemo()
        {
            MidiFile mf;

            using (var idev = MidiDevice.Inputs[0])
            {
                using (var odev = MidiDevice.Outputs[0])
                {
                    idev.Input += delegate(object s, MidiInputEventArgs e)
                    {
                        // this is so we can pass through and hear
                        // our input while recording
                        odev.Send(e.Message);
                    };
                    idev.TempoChanged += delegate(object s, EventArgs e)
                    {
                        Console.WriteLine("New Tempo: " + idev.Tempo);
                    };
                    // open the input
                    // and output
                    idev.Open();
                    // set our timebase
                    idev.TimeBase = 384;
                    odev.Open();
                    idev.Start();
                    // start recording, waiting for input
                    idev.StartRecording(true);
                    // wait to end it
                    Console.Error.WriteLine("Press any key to stop recording...");
                    Console.ReadKey();
                    // get our MidiFile from this
                    mf = idev.EndRecording();
                    // the MIDI file is always two
                    // tracks, with the first track
                    // being the tempo map
                }
            }
            if (null == mf)
            {
                return;
            }
            // merge for playback
            var seq = MidiSequence.Merge(mf.Tracks);

            // now stream the file to the output
            // just grab the first output stream
            using (var stm = MidiDevice.Streams[0])
            {
                // open it
                stm.Open();
                // merge the tracks for playback
                seq = MidiSequence.Merge(mf.Tracks);
                // set the stream timebase
                stm.TimeBase = mf.TimeBase;
                // start the playback
                stm.Start();
                Console.Error.WriteLine("Press any key to exit...");
                // if we weren't looping
                // we wouldn't need to
                // hook this:
                stm.SendComplete += delegate(object s, EventArgs e)
                {
                    // loop
                    stm.Send(seq.Events);
                };
                // kick things off
                stm.Send(seq.Events);
                // wait for exit
                Console.ReadKey();
            }
        }
Exemplo n.º 12
0
        static void ComplexStreamingDemo()
        {
            // demonstrate streaming a midi file 100 events at a time
            // this allows you to handle files with more than 64kb
            // of in-memory events (not the same as "on disk" size)
            // this replays the events in a loop
            var midiFile = MidiFile
                           //.ReadFrom(@"..\..\Bohemian-Rhapsody-1.mid"); // > 64kb!
                           .ReadFrom(@"..\..\A-Warm-Place.mid");

            //.ReadFrom(@"..\..\GORILLAZ_-_Feel_Good_Inc.mid");
            //.ReadFrom(@"..\..\Feel_good_4beatsBass.mid");
            //.ReadFrom(@"..\..\THE BEASTIE BOYS.Sabotage.mid");
            //.ReadFrom(@"..\..\Peter-Gunn-1.mid");
            Console.WriteLine(Path.GetFileName(midiFile.FilePath) + " @ " + midiFile.TimeBase + " PQN");
            var tsig = midiFile.TimeSignature;

            Console.WriteLine("Tempo: " + midiFile.Tempo + " BPM @ " + tsig.Numerator + "/" + tsig.Denominator + " time");
            Console.WriteLine("Tracks:");
            for (var i = 0; i < midiFile.Tracks.Count; ++i)
            {
                var track = midiFile.Tracks[i];
                Console.Write("\t");
                var name = track.Name;
                if (string.IsNullOrEmpty(name))
                {
                    name = "Track " + i;
                }
                Console.WriteLine(name + " \tEvents: " + track.Events.Count);
            }
            Console.WriteLine();
            // we use 100 events, which should be safe and allow
            // for some measure of SYSEX messages in the stream
            // without bypassing the 64kb limit
            const int EVENT_COUNT = 100;
            // our current cursor pos
            int pos = 0;
            // merge our file for playback
            var seq = MidiSequence.Merge(midiFile.Tracks);
            // the number of events in the seq
            int len = seq.Events.Count;
            // stores the next set of events
            var eventList = new List <MidiEvent>(EVENT_COUNT);

            // just grab the first output stream
            // should be the wavetable synth
            using (var stm = MidiDevice.Streams[0])
            {
                // open the stream
                stm.Open();
                // start it
                stm.Start();
                // first set the timebase
                stm.TimeBase = midiFile.TimeBase;

                // set up our send complete handler
                stm.SendComplete += delegate(object sender, EventArgs eargs)
                {
                    // clear the list
                    eventList.Clear();
                    // iterate through the next events
                    var next = pos + EVENT_COUNT;
                    for (; pos < next; ++pos)
                    {
                        // if it's past the end, loop it
                        if (len <= pos)
                        {
                            pos = 0;
                            break;
                        }
                        // otherwise add the next event
                        eventList.Add(seq.Events[pos]);
                    }
                    // send the list of events
                    stm.SendDirect(eventList);
                };
                // add the first events
                for (pos = 0; pos < EVENT_COUNT; ++pos)
                {
                    // if it's past the end, loop it
                    if (len <= pos)
                    {
                        pos = 0;
                        break;
                    }
                    // otherwise add the next event
                    eventList.Add(seq.Events[pos]);
                }
                // send the list of events
                stm.SendDirect(eventList);

                // loop until a key is pressed
                Console.Error.WriteLine("Press any key to exit...");
                Console.ReadKey();
                // close the stream
                stm.Close();
            }
        }
Exemplo n.º 13
0
        private void PlayButton_Click(object sender, EventArgs e)
        {
            if ("Stop" == PlayButton.Text)
            {
                PlayButton.Text = "Play";
                if (null != _outputStream)
                {
                    _outputStream.Close();
                }
                MidiOutComboBox.Enabled  = true;
                FileTextBox.Enabled      = true;
                FileBrowseButton.Enabled = true;
                Visualizer.ShowCursor    = false;
                return;
            }
            PlayButton.Text           = "Stop";
            Visualizer.CursorPosition = 0;
            Visualizer.ShowCursor     = true;
            MidiOutComboBox.Enabled   = false;
            FileTextBox.Enabled       = false;
            FileBrowseButton.Enabled  = false;
            var mf = MidiFile.ReadFrom(FileTextBox.Text);

            if (null != _outputStream)
            {
                // BUG: For some reason recycling the output stream
                // screws up playback on successive uses. I have had
                // no luck tracking down why so far. The following
                // causes the MidiStream class to be recreated
                // instead of recycled
                var stm = _outputStream = MidiDevice.Streams[_outputStream.Index];
                // we use 100 events, which should be safe and allow
                // for some measure of SYSEX messages in the stream
                // without bypassing the 64kb limit
                const int MAX_EVENT_COUNT = 100;
                // the lower this is, the more more CPU it takes.
                // the higher it is, the less accurate the cursor
                // position will be:
                const int RATE_TICKS = 10;
                // our current cursor pos
                var pos = 0;
                // for tracking deltas
                var ofs = 0;
                // for tracking the song position
                var songPos   = 0;
                var songTicks = 0;
                // merge our file for playback
                var seq    = MidiSequence.Merge(mf.Tracks);
                var events = seq.Events;
                // the number of events in the seq
                var len = events.Count;
                // stores the next set of events
                var eventList = new List <MidiEvent>(MAX_EVENT_COUNT);

                // open the stream
                stm.Open();
                if (MidiOutputDeviceVolumeSupport.None != stm.VolumeSupport)
                {
                    stm.Volume = new MidiVolume((byte)VolumeKnob.Value, (byte)VolumeKnob.Value);
                }

                // start it
                stm.Start();

                // first set the timebase
                stm.TimeBase = mf.TimeBase;
                // set up our send complete handler
                stm.SendComplete += delegate(object s, EventArgs ea)
                {
                    try
                    {
                        BeginInvoke(new Action(delegate()
                        {
                            // clear the list
                            eventList.Clear();

                            ofs = 0;
                            len = events.Count;
                            // iterate through the next events
                            var next = pos + MAX_EVENT_COUNT;
                            for (; pos < next && ofs <= RATE_TICKS; ++pos)

                            {
                                // if it's past the end, loop it
                                if (len <= pos)
                                {
                                    pos       = 0;
                                    songPos   = 0;
                                    songTicks = 0;
                                    events    = seq.Events;
                                    break;
                                }
                                var ev     = events[pos];
                                ofs       += ev.Position;
                                songTicks += ev.Position;
                                songPos   += pos;
                                if (ev.Position < RATE_TICKS && RATE_TICKS < ofs)
                                {
                                    break;
                                }
                                // otherwise add the next event
                                eventList.Add(ev);
                            }
                            // send the list of events
                            if (MidiStreamState.Closed != stm.State && 0 != eventList.Count)
                            {
                                stm.SendDirect(eventList);
                            }
                            Visualizer.CursorPosition = songTicks;
                        }));
                    }
                    catch { }
                };
                // add the first events
                for (pos = 0; pos < MAX_EVENT_COUNT && ofs <= RATE_TICKS; ++pos)
                {
                    // if it's past the end, loop it
                    if (len <= pos)
                    {
                        pos       = 0;
                        songPos   = 0;
                        songTicks = 0;
                        events    = seq.Events;
                        break;
                    }
                    var ev = events[pos];
                    ofs       += ev.Position;
                    songTicks += ev.Position;
                    if (ev.Position < RATE_TICKS && RATE_TICKS < ofs)
                    {
                        break;
                    }
                    // otherwise add the next event
                    eventList.Add(ev);
                }
                Visualizer.CursorPosition = songTicks;
                // send the list of events
                if (0 != eventList.Count)
                {
                    stm.SendDirect(eventList);
                }
            }
        }
Exemplo n.º 14
0
        private void PlayButton_Click(object sender, EventArgs e)
        {
            // we use 100 events, which should be safe and allow
            // for some measure of SYSEX messages in the stream
            // without bypassing the 64kb limit
            const int MAX_EVENT_COUNT = 100;
            const int RATE_TICKS      = 500;

            if ("Stop" == PlayButton.Text)
            {
                if (null != _play)              // sanity check
                {
                    _play.Close();
                }
                PlayButton.Text         = "Play";
                PatternComboBox.Enabled = true;
                BarsUpDown.Enabled      = true;
                OutputComboBox.Enabled  = true;
                return;
            }
            PatternComboBox.Enabled = false;
            BarsUpDown.Enabled      = false;
            OutputComboBox.Enabled  = false;
            PlayButton.Text         = "Stop";

            _play = (OutputComboBox.SelectedItem as MidiOutputDevice).Stream;
            var mf  = _CreateMidiFile();
            var stm = _play;

            // our current cursor pos
            int pos = 0;
            // for tracking deltas
            var ofs = 0;
            // merge our file for playback
            var seq = MidiSequence.Merge(mf.Tracks);
            // the number of events in the seq
            int len = seq.Events.Count;
            // stores the next set of events
            var eventList = new List <MidiEvent>(MAX_EVENT_COUNT);

            // open the stream
            stm.Open();
            // start it
            stm.Start();

            // first set the timebase
            stm.TimeBase = mf.TimeBase;

            // set up our send complete handler
            stm.SendComplete += delegate(object s, EventArgs ea)
            {
                try
                {
                    BeginInvoke(new Action(delegate()
                    {
                        // clear the list
                        eventList.Clear();
                        mf  = _CreateMidiFile();
                        seq = MidiSequence.Merge(mf.Tracks);
                        ofs = 0;
                        len = seq.Events.Count;
                        // iterate through the next events
                        var next = pos + MAX_EVENT_COUNT;
                        for (; pos < next && ofs <= RATE_TICKS; ++pos)

                        {
                            // if it's past the end, loop it
                            if (len <= pos)
                            {
                                pos = 0;
                                break;
                            }
                            var ev = seq.Events[pos];
                            ofs   += ev.Position;
                            if (ev.Position < RATE_TICKS && RATE_TICKS < ofs)
                            {
                                break;
                            }
                            // otherwise add the next event
                            eventList.Add(ev);
                        }
                        // send the list of events
                        if (MidiStreamState.Closed != stm.State)
                        {
                            stm.SendDirect(eventList);
                        }
                    }));
                }
                catch
                {
                }
            };
            // add the first events
            for (pos = 0; pos < MAX_EVENT_COUNT && ofs <= RATE_TICKS; ++pos)
            {
                // if it's past the end, loop it
                if (len <= pos)
                {
                    pos = 0;
                    break;
                }
                var ev = seq.Events[pos];
                ofs += ev.Position;
                if (ev.Position < RATE_TICKS && RATE_TICKS < ofs)
                {
                    break;
                }
                // otherwise add the next event
                eventList.Add(ev);
            }
            // send the list of events
            stm.SendDirect(eventList);
        }
Exemplo n.º 15
0
        MidiFile _CreateMidiFile()
        {
            var file = new MidiFile();
            // we'll need a track 0 for our tempo map
            var track0 = new MidiSequence();

            // set the tempo at the first position
            track0.Events.Add(new MidiEvent(0, new MidiMessageMetaTempo((double)TempoUpDown.Value)));
            // compute the length of our loop
            var len = ((int)BarsUpDown.Value) * 4 * file.TimeBase;

            // add an end of track marker just so all
            // of our tracks will be the loop length
            track0.Events.Add(new MidiEvent(len, new MidiMessageMetaEndOfTrack()));

            // here we need a track end with an
            // absolute position for the MIDI end
            // of track meta message. We'll use this
            // later to set the length of the track
            var trackEnd = new MidiSequence();

            trackEnd.Events.Add(new MidiEvent(len, new MidiMessageMetaEndOfTrack()));

            // add track 0 (our tempo map)
            file.Tracks.Add(track0);

            // create track 1 (our drum track)
            var track1 = new MidiSequence();

            // we're going to create a new sequence for
            // each one of the drum sequencer tracks in
            // the UI
            var trks = new List <MidiSequence>(BeatsPanel.Controls.Count);

            foreach (var ctl in BeatsPanel.Controls)
            {
                var beat = ctl as BeatControl;
                // get the note for the drum
                var note = beat.NoteId;
                // it's easier to use a note map
                // to build the drum sequence
                var noteMap = new List <MidiNote>();
                for (int ic = beat.Steps.Count, i = 0; i < ic; ++i)
                {
                    // if the step is pressed create
                    // a note for it
                    if (beat.Steps[i])
                    {
                        noteMap.Add(new MidiNote(i * (file.TimeBase / 4), 9, note, 127, file.TimeBase / 4 - 1));
                    }
                }
                // convert the note map to a sequence
                // and add it to our working tracks
                trks.Add(MidiSequence.FromNoteMap(noteMap));
            }
            // now we merge the sequences into one
            var t = MidiSequence.Merge(trks);

            // we merge everything down to track 1
            track1 = MidiSequence.Merge(track1, t, trackEnd);
            // .. and add it to the file
            file.Tracks.Add(track1);
            return(file);
        }
Exemplo n.º 16
0
        private void PreviewButton_Click(object sender, EventArgs e)
        {
            if ("Stop" == PreviewButton.Text)
            {
                if (null != _previewThread)
                {
                    _previewThread.Abort();
                    _previewThread.Join();
                    _previewThread = null;
                }
                PreviewButton.Text = "Preview";
                return;
            }
            var f = _file;

            if (ResampleUpDown.Value != _file.TimeBase)
            {
                f = _file.Resample(unchecked ((short)ResampleUpDown.Value));
            }
            var trks = new List <MidiSequence>(f.Tracks.Count);

            for (int ic = TrackList.Items.Count, i = 0; i < ic; ++i)
            {
                if (TrackList.CheckedItems.Contains(TrackList.Items[i]))
                {
                    trks.Add(f.Tracks[i]);
                }
            }
            var trk = MidiSequence.Merge(trks);
            var ofs = (int)OffsetUpDown.Value;
            var len = (int)LengthUpDown.Value;

            if (0 == UnitsCombo.SelectedIndex)             // beats
            {
                len = (int)Math.Min(Math.Ceiling(len * (decimal)f.TimeBase), f.Length);
                ofs = (int)Math.Min(Math.Ceiling(ofs * (decimal)f.TimeBase), f.Length);
            }
            switch (StartCombo.SelectedIndex)
            {
            case 1:
                ofs += f.FirstDownBeat;
                break;

            case 2:
                ofs += f.FirstNoteOn;
                break;
            }
            if (0 != ofs && CopyTimingPatchCheckBox.Checked)
            {
                var end = trk.FirstNoteOn;
                if (0 == end)
                {
                    end = trk.Length;
                }
                var trk2 = trk.GetRange(ofs, len);
                var ins  = 0;
                for (int ic = trk.Events.Count, i = 0; i < ic; ++i)
                {
                    var ev = trk.Events[i];
                    if (ev.Position >= end)
                    {
                        break;
                    }
                    var m = ev.Message;
                    switch (m.Status)
                    {
                    case 0xFF:
                        var mm = m as MidiMessageMeta;
                        switch (mm.Data1)
                        {
                        case 0x51:
                        case 0x54:
                            trk2.Events.Insert(ins, ev.Clone());
                            ++ins;
                            break;
                        }
                        break;

                    default:
                        if (0xC0 == (ev.Message.Status & 0xF0))
                        {
                            trk2.Events.Insert(ins, ev.Clone());
                            ++ins;
                        }
                        break;
                    }
                }
                trk = trk2;
            }
            else
            {
                if (trk.Length != len || 0 != ofs)
                {
                    trk = trk.GetRange(ofs, len);
                }
            }
            if (1m != StretchUpDown.Value)
            {
                trk = trk.Stretch((double)StretchUpDown.Value, AdjustTempoCheckBox.Checked);
            }

            if (null != _previewThread)
            {
                _previewThread.Abort();
                _previewThread.Join();
                _previewThread = null;
            }
            PreviewButton.Text = "Stop";
            _previewThread     = new Thread(() => { trk.Preview(f.TimeBase, 0, true); });
            _previewThread.Start();
        }