Ejemplo n.º 1
0
        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Console.WriteLine("Usage AlphaTab.ScoreDump.exe PathToFile PathToSoundFont");
                return;
            }

            // load score
            var score = ScoreLoader.LoadScoreFromBytes(File.ReadAllBytes(args[0]));

            // generate midi
            var midiFile  = new MidiFile();
            var handler   = new AlphaSynthMidiFileHandler(midiFile);
            var generator = new MidiFileGenerator(score, null, handler);

            generator.Generate();

            var player = new AlphaSynth(new NAudioSynthOutput());

            player.MidiLoaded          += () => { Console.WriteLine("Midi loaded"); };
            player.SoundFontLoaded     += () => { Console.WriteLine("SoundFont loaded"); };
            player.MidiLoadFailed      += e => { Console.WriteLine("Midi load failed"); };
            player.SoundFontLoadFailed += e => { Console.WriteLine("SoundFont load failed"); };
            player.Finished            += _ =>
            {
                Console.WriteLine("Playback finished");
                ((NAudioSynthOutput)player.Output).Close();
            };
            player.PositionChanged += e =>
            {
                TimeSpan currentTime = TimeSpan.FromMilliseconds(e.CurrentTime);
                TimeSpan endTime     = TimeSpan.FromMilliseconds(e.EndTime);

                Console.CursorTop--;
                Console.Write("".PadLeft(Console.BufferWidth - 1, ' '));
                Console.CursorLeft = 0;
                Console.WriteLine("{0:mm\\:ss\\:fff} ({1}) of {2:mm\\:ss\\:fff} ({3})",
                                  currentTime, e.CurrentTick, endTime, e.EndTick);
            };
            player.ReadyForPlayback += () =>
            {
                Console.WriteLine("Ready for playback");
            };
            player.LoadSoundFont(File.ReadAllBytes(args[1]));
            player.LoadMidi(midiFile);

            Console.WriteLine("Start playing");
            player.Play();

            Console.WriteLine("Press enter to exit");
            Console.ReadLine();

            player.Pause();

            Console.ReadLine();
        }
Ejemplo n.º 2
0
        public void TestPcmGeneration()
        {
            var tex = "\\tempo 102 \\tuning E4 B3 G3 D3 A2 E2 \\instrument 25 . r.8 (0.4 0.3 ).8 " +
                      "(-.3 -.4 ).2 {d } | (0.4 0.3 ).8 r.8 (3.3 3.4 ).8 r.8 (5.4 5.3 ).4 r.8 (0.4 0.3 ).8 |" +
                      " r.8 (3.4 3.3 ).8 r.8 (6.3 6.4 ).8 (5.4 5.3 ).4 {d }r.8 |" +
                      " (0.4 0.3).8 r.8(3.4 3.3).8 r.8(5.4 5.3).4 r.8(3.4 3.3).8 | " +
                      "r.8(0.4 0.3).8(-.3 - .4).2 { d } | ";
            var importer = new AlphaTexImporter();

            importer.Init(TestPlatform.CreateStringReader(tex));
            var score = importer.ReadScore();

            var midi = new MidiFile();
            var gen  = new MidiFileGenerator(score, null, new AlphaSynthMidiFileHandler(midi));

            gen.Generate();

            var testOutput = new TestOutput();
            var synth      = new AlphaSynth(testOutput);

            synth.LoadSoundFont(TestPlatform.LoadFile("TestFiles/Audio/default.sf2"));
            synth.LoadMidi(midi);

            synth.Play();

            var finished = false;

            synth.Finished += b => finished = true;

            while (!finished)
            {
                testOutput.Continue();
            }

            //Console.WriteLine(testOutput.Samples.Count);
            //using (var writer = new BinaryWriter(new FileStream("test.pcm", FileMode.Create, FileAccess.Write)))
            //{
            //    for (int i = 0; i < testOutput.Samples.Count; i++)
            //    {
            //        writer.Write(testOutput.Samples[i]);
            //    }
            //}
        }
Ejemplo n.º 3
0
        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Usage AlphaTab.MidiDump.exe Path");
                return;
            }

            // load score
            var score = ScoreLoader.LoadScoreFromBytes(File.ReadAllBytes(args[0]));

            // generate midi
            MidiFile file = MidiFileGenerator.GenerateMidiFile(score);

            // write midi file
            string path = Path.ChangeExtension(args[0], "mid");

            using (var fs = new StreamWrapper(File.OpenWrite(path)))
            {
                file.WriteTo(fs);
            }
        }
Ejemplo n.º 4
0
        public void TestBend()
        {
            var tex   = ":4 15.6{b(0 4)} 15.6";
            var score = ParseTex(tex);

            Assert.AreEqual(1, score.Tracks.Count);
            Assert.AreEqual(1, score.Tracks[0].Bars.Count);
            Assert.AreEqual(1, score.Tracks[0].Bars[0].Voices.Count);
            Assert.AreEqual(2, score.Tracks[0].Bars[0].Voices[0].Beats.Count);
            Assert.AreEqual(1, score.Tracks[0].Bars[0].Voices[0].Beats[0].Notes.Count);
            Assert.AreEqual(1, score.Tracks[0].Bars[0].Voices[0].Beats[1].Notes.Count);

            var handler   = new FlatMidiEventGenerator();
            var generator = new MidiFileGenerator(score, handler);

            generator.Generate();

            var info = score.Tracks[0].PlaybackInfo;
            var note = score.Tracks[0].Bars[0].Voices[0].Beats[0].Notes[0];

            var expectedEvents = new FlatMidiEventGenerator.MidiEvent[]
            {
                // channel init
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.Volume, Value = 120
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.Balance, Value = 64
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.Expression, Value = 127
                },
                new FlatMidiEventGenerator.ProgramChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Program = (byte)info.Program
                },

                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.Volume, Value = 120
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.Balance, Value = 64
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.Expression, Value = 127
                },
                new FlatMidiEventGenerator.ProgramChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Program = (byte)info.Program
                },

                new FlatMidiEventGenerator.TimeSignatureEvent {
                    Tick = 0, Numerator = 4, Denominator = 4
                },
                new FlatMidiEventGenerator.TempoEvent {
                    Tick = 0, Tempo = 120
                },

                // bend effect
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Value = 64
                },                                                                                                       // no bend
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 87, Track = 0, Channel = info.PrimaryChannel, Value = 65
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 174, Track = 0, Channel = info.PrimaryChannel, Value = 66
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 261, Track = 0, Channel = info.PrimaryChannel, Value = 67
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 349, Track = 0, Channel = info.PrimaryChannel, Value = 68
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 436, Track = 0, Channel = info.PrimaryChannel, Value = 69
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 523, Track = 0, Channel = info.PrimaryChannel, Value = 70
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 610, Track = 0, Channel = info.PrimaryChannel, Value = 71
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 698, Track = 0, Channel = info.PrimaryChannel, Value = 72
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 785, Track = 0, Channel = info.PrimaryChannel, Value = 73
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 872, Track = 0, Channel = info.PrimaryChannel, Value = 74
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 959, Track = 0, Channel = info.PrimaryChannel, Value = 75
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 960, Track = 0, Channel = info.PrimaryChannel, Value = 64
                },

                // note itself
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, DynamicValue = note.Dynamic, Key = (byte)note.RealValue, Length = note.Beat.Duration.ToTicks()
                },
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = 960, Track = 0, Channel = info.PrimaryChannel, DynamicValue = note.Dynamic, Key = (byte)note.RealValue, Length = note.Beat.Duration.ToTicks()
                }
            };

            for (int i = 0; i < handler.MidiEvents.Count; i++)
            {
                Console.WriteLine("i[{0}] {1}", i, handler.MidiEvents[i]);
                if (i < expectedEvents.Length)
                {
                    Assert.AreEqual(expectedEvents[i], handler.MidiEvents[i]);
                }
            }

            Assert.AreEqual(expectedEvents.Length, handler.MidiEvents.Count);
        }
Ejemplo n.º 5
0
        public void TestBendMultiPoint()
        {
            var tex   = ":4 15.6{b(0 4 0)} 15.6";
            var score = ParseTex(tex);

            Assert.AreEqual(1, score.Tracks.Count);
            Assert.AreEqual(1, score.Tracks[0].Staves[0].Bars.Count);
            Assert.AreEqual(1, score.Tracks[0].Staves[0].Bars[0].Voices.Count);
            Assert.AreEqual(2, score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats.Count);
            Assert.AreEqual(1, score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0].Notes.Count);
            Assert.AreEqual(1, score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[1].Notes.Count);

            var handler   = new FlatMidiEventGenerator();
            var generator = new MidiFileGenerator(score, handler);

            generator.Generate();

            var info = score.Tracks[0].PlaybackInfo;
            var note = score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0].Notes[0];

            var expectedEvents = new FlatMidiEventGenerator.MidiEvent[]
            {
                // channel init
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.VolumeCoarse, Value = 120
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.PanCoarse, Value = 64
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.ExpressionControllerCoarse, Value = 127
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.RegisteredParameterFine, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.RegisteredParameterCourse, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.DataEntryFine, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)MidiController.DataEntryCoarse, Value = 12
                },
                new FlatMidiEventGenerator.ProgramChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Program = (byte)info.Program
                },

                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.VolumeCoarse, Value = 120
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.PanCoarse, Value = 64
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.ExpressionControllerCoarse, Value = 127
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.RegisteredParameterFine, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.RegisteredParameterCourse, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.DataEntryFine, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)MidiController.DataEntryCoarse, Value = 12
                },
                new FlatMidiEventGenerator.ProgramChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Program = (byte)info.Program
                },

                new FlatMidiEventGenerator.TimeSignatureEvent {
                    Tick = 0, Numerator = 4, Denominator = 4
                },
                new FlatMidiEventGenerator.TempoEvent {
                    Tick = 0, Tempo = 120
                },

                // bend effect
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Value = 64
                },                                                                                                       // no bend
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 43, Track = 0, Channel = info.PrimaryChannel, Value = 65
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 87, Track = 0, Channel = info.PrimaryChannel, Value = 66
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 130, Track = 0, Channel = info.PrimaryChannel, Value = 67
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 174, Track = 0, Channel = info.PrimaryChannel, Value = 68
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 218, Track = 0, Channel = info.PrimaryChannel, Value = 69
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 261, Track = 0, Channel = info.PrimaryChannel, Value = 70
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 305, Track = 0, Channel = info.PrimaryChannel, Value = 71
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 349, Track = 0, Channel = info.PrimaryChannel, Value = 72
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 392, Track = 0, Channel = info.PrimaryChannel, Value = 73
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 436, Track = 0, Channel = info.PrimaryChannel, Value = 74
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 479, Track = 0, Channel = info.PrimaryChannel, Value = 75
                },                                                                                                         // full bend

                new FlatMidiEventGenerator.BendEvent {
                    Tick = 480, Track = 0, Channel = info.PrimaryChannel, Value = 75
                },                                                                                                         // full bend
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 523, Track = 0, Channel = info.PrimaryChannel, Value = 74
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 567, Track = 0, Channel = info.PrimaryChannel, Value = 73
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 610, Track = 0, Channel = info.PrimaryChannel, Value = 72
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 654, Track = 0, Channel = info.PrimaryChannel, Value = 71
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 698, Track = 0, Channel = info.PrimaryChannel, Value = 70
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 741, Track = 0, Channel = info.PrimaryChannel, Value = 69
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 785, Track = 0, Channel = info.PrimaryChannel, Value = 68
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 829, Track = 0, Channel = info.PrimaryChannel, Value = 67
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 872, Track = 0, Channel = info.PrimaryChannel, Value = 66
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 916, Track = 0, Channel = info.PrimaryChannel, Value = 65
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 959, Track = 0, Channel = info.PrimaryChannel, Value = 64
                },                                                                                                         // no bend

                // note itself
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, DynamicValue = note.Dynamic, Key = (byte)note.RealValue, Length = note.Beat.Duration.ToTicks()
                },

                // reset bend
                new FlatMidiEventGenerator.BendEvent {
                    Tick = 960, Track = 0, Channel = info.PrimaryChannel, Value = 64
                },                                                                                                         // finish
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = 960, Track = 0, Channel = info.PrimaryChannel, DynamicValue = note.Dynamic, Key = (byte)note.RealValue, Length = note.Beat.Duration.ToTicks()
                },
                // end of track
                new FlatMidiEventGenerator.TrackEndEvent {
                    Tick = 3840, Track = 0
                }                                                                   // 3840 = end of bar
            };

            for (int i = 0; i < handler.MidiEvents.Count; i++)
            {
                Console.WriteLine("i[{0}] {1}", i, handler.MidiEvents[i]);
                if (i < expectedEvents.Length)
                {
                    Assert.AreEqual(expectedEvents[i], handler.MidiEvents[i]);
                }
            }

            Assert.AreEqual(expectedEvents.Length, handler.MidiEvents.Count);
        }
Ejemplo n.º 6
0
        public void TestGraceBeatGeneration()
        {
            var reader = new Gp7Importer();
            var buffer = TestPlatform.LoadFile("TestFiles/Audio/GraceBeats.gp");

            var settings = Settings.SongBook;

            reader.Init(ByteBuffer.FromBuffer(buffer), settings);
            var score = reader.ReadScore();

            var handler   = new FlatMidiEventGenerator();
            var generator = new MidiFileGenerator(score, settings, handler);

            generator.Generate();

            // on beat
            var tick  = 0;
            var ticks = new FastList <int>();

            Assert.AreEqual(tick, score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0].AbsolutePlaybackStart);
            Assert.AreEqual(3840, score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0].PlaybackDuration);
            ticks.Add(tick);
            tick += score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0].PlaybackDuration;

            Assert.AreEqual(tick, score.Tracks[0].Staves[0].Bars[1].Voices[0].Beats[0].AbsolutePlaybackStart);
            Assert.AreEqual(120, score.Tracks[0].Staves[0].Bars[1].Voices[0].Beats[0].PlaybackDuration);
            ticks.Add(tick);
            tick += score.Tracks[0].Staves[0].Bars[1].Voices[0].Beats[0].PlaybackDuration;

            Assert.AreEqual(tick, score.Tracks[0].Staves[0].Bars[1].Voices[0].Beats[1].AbsolutePlaybackStart);
            Assert.AreEqual(3720, score.Tracks[0].Staves[0].Bars[1].Voices[0].Beats[1].PlaybackDuration);
            ticks.Add(tick);
            tick += score.Tracks[0].Staves[0].Bars[1].Voices[0].Beats[1].PlaybackDuration;

            // before beat
            Assert.AreEqual(tick, score.Tracks[0].Staves[0].Bars[2].Voices[0].Beats[0].AbsolutePlaybackStart);
            Assert.AreEqual(3720, score.Tracks[0].Staves[0].Bars[2].Voices[0].Beats[0].PlaybackDuration);
            ticks.Add(tick);
            tick += score.Tracks[0].Staves[0].Bars[2].Voices[0].Beats[0].PlaybackDuration;

            Assert.AreEqual(tick, score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[0].AbsolutePlaybackStart);
            Assert.AreEqual(120, score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[0].PlaybackDuration);
            ticks.Add(tick);
            tick += score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[0].PlaybackDuration;

            Assert.AreEqual(tick, score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[1].AbsolutePlaybackStart);
            Assert.AreEqual(3840, score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[1].PlaybackDuration);
            ticks.Add(tick);
            tick += score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[1].PlaybackDuration;

            // bend
            Assert.AreEqual(GraceType.BendGrace, score.Tracks[0].Staves[0].Bars[4].Voices[0].Beats[0].GraceType);
            Assert.AreEqual(tick, score.Tracks[0].Staves[0].Bars[4].Voices[0].Beats[0].AbsolutePlaybackStart);
            Assert.AreEqual(1920, score.Tracks[0].Staves[0].Bars[4].Voices[0].Beats[0].PlaybackDuration);
            ticks.Add(tick);
            tick += score.Tracks[0].Staves[0].Bars[4].Voices[0].Beats[0].PlaybackDuration;

            Assert.AreEqual(tick, score.Tracks[0].Staves[0].Bars[4].Voices[0].Beats[1].AbsolutePlaybackStart);
            Assert.AreEqual(1920, score.Tracks[0].Staves[0].Bars[4].Voices[0].Beats[1].PlaybackDuration);
            ticks.Add(tick);
            tick += score.Tracks[0].Staves[0].Bars[4].Voices[0].Beats[1].PlaybackDuration;

            var info           = score.Tracks[0].PlaybackInfo;
            var expectedEvents = new FlatMidiEventGenerator.MidiEvent[]
            {
                // channel init
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)ControllerType.VolumeCoarse, Value = 120
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)ControllerType.PanCoarse, Value = 64
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)ControllerType.ExpressionControllerCoarse, Value = 127
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)ControllerType.RegisteredParameterFine, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)ControllerType.RegisteredParameterCourse, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)ControllerType.DataEntryFine, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Controller = (byte)ControllerType.DataEntryCoarse, Value = 12
                },
                new FlatMidiEventGenerator.ProgramChangeEvent {
                    Tick = 0, Track = 0, Channel = info.PrimaryChannel, Program = (byte)info.Program
                },

                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)ControllerType.VolumeCoarse, Value = 120
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)ControllerType.PanCoarse, Value = 64
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)ControllerType.ExpressionControllerCoarse, Value = 127
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)ControllerType.RegisteredParameterFine, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)ControllerType.RegisteredParameterCourse, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)ControllerType.DataEntryFine, Value = 0
                },
                new FlatMidiEventGenerator.ControlChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Controller = (byte)ControllerType.DataEntryCoarse, Value = 12
                },
                new FlatMidiEventGenerator.ProgramChangeEvent {
                    Tick = 0, Track = 0, Channel = info.SecondaryChannel, Program = (byte)info.Program
                },

                new FlatMidiEventGenerator.TimeSignatureEvent {
                    Tick = 0, Numerator = 4, Denominator = 4
                },
                new FlatMidiEventGenerator.TempoEvent {
                    Tick = 0, Tempo = 120
                },

                // on beat
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[0], Track = 0, Channel = info.PrimaryChannel, Value = 64
                },
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = ticks[0], Track = 0, Channel = info.PrimaryChannel, DynamicValue = DynamicValue.F, Key = (byte)67, Length = 3840
                },

                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[1], Track = 0, Channel = info.PrimaryChannel, Value = 64
                },
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = ticks[1], Track = 0, Channel = info.PrimaryChannel, DynamicValue = DynamicValue.F, Key = (byte)67, Length = 120
                },

                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[2], Track = 0, Channel = info.PrimaryChannel, Value = 64
                },
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = ticks[2], Track = 0, Channel = info.PrimaryChannel, DynamicValue = DynamicValue.F, Key = (byte)67, Length = 3720
                },


                // before beat
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[3], Track = 0, Channel = info.PrimaryChannel, Value = 64
                },
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = ticks[3], Track = 0, Channel = info.PrimaryChannel, DynamicValue = DynamicValue.F, Key = (byte)67, Length = 3720
                },

                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[4], Track = 0, Channel = info.PrimaryChannel, Value = 64
                },
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = ticks[4], Track = 0, Channel = info.PrimaryChannel, DynamicValue = DynamicValue.F, Key = (byte)67, Length = 120
                },

                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[5], Track = 0, Channel = info.PrimaryChannel, Value = 64
                },
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = ticks[5], Track = 0, Channel = info.PrimaryChannel, DynamicValue = DynamicValue.F, Key = (byte)67, Length = 3840
                },

                // bend beat
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6], Track = 0, Channel = info.SecondaryChannel, Value = 64
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 0, Track = 0, Channel = info.SecondaryChannel, Value = 64
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 1, Track = 0, Channel = info.SecondaryChannel, Value = 65
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 2, Track = 0, Channel = info.SecondaryChannel, Value = 66
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 3, Track = 0, Channel = info.SecondaryChannel, Value = 67
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 4, Track = 0, Channel = info.SecondaryChannel, Value = 68
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 5, Track = 0, Channel = info.SecondaryChannel, Value = 69
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 6, Track = 0, Channel = info.SecondaryChannel, Value = 70
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 7, Track = 0, Channel = info.SecondaryChannel, Value = 71
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 8, Track = 0, Channel = info.SecondaryChannel, Value = 72
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 9, Track = 0, Channel = info.SecondaryChannel, Value = 73
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 10, Track = 0, Channel = info.SecondaryChannel, Value = 74
                },
                new FlatMidiEventGenerator.BendEvent {
                    Tick = ticks[6] + 13 * 11 + 1, Track = 0, Channel = info.SecondaryChannel, Value = 75
                },
                new FlatMidiEventGenerator.NoteEvent {
                    Tick = ticks[6], Track = 0, Channel = info.SecondaryChannel, Length = 3840, Key = 67, DynamicValue = DynamicValue.F
                },

                // end of track
                new FlatMidiEventGenerator.TrackEndEvent {
                    Tick = 19200, Track = 0
                }                                                                    // 3840 = end of bar
            };

            for (int i = 0; i < handler.MidiEvents.Count; i++)
            {
                Logger.Info("Test", $"i[{i}] {handler.MidiEvents[i]}");
                if (i < expectedEvents.Length)
                {
                    Assert.AreEqual(expectedEvents[i], handler.MidiEvents[i]);
                }
            }

            Assert.AreEqual(expectedEvents.Length, handler.MidiEvents.Count);
        }