示例#1
0
        public void Flip_Should_Flip_From_Middle_When_Changing_Octave_Is_Not_Possible()
        {
            //Arrange
            MidiService target     = new MidiService();
            Stream      midiStream = File.Open($"{TestFilesPath}flip_from_middle_0_127.mid", FileMode.Open);
            const int   firstNote  = 127;
            const int   secondNote = 64;
            const int   thirdNote  = 63;
            const int   lastNote   = 0;

            //Act
            Stream flippedMidiStream = target.Flip(midiStream, 0);

            //Assert
            MidiSequence flippedMidi       = MidiSequence.Open(flippedMidiStream);
            int          firstFlippedNote  = flippedMidi.Tracks[2].Events.OfType <OnNoteVoiceMidiEvent>().First().Note;
            int          secondFlippedNote = flippedMidi.Tracks[2].Events.OfType <OnNoteVoiceMidiEvent>().ElementAt(1).Note;
            int          thirdFlippedNote  = flippedMidi.Tracks[2].Events.OfType <OnNoteVoiceMidiEvent>().ElementAt(2).Note;
            int          lastFlippedNote   = flippedMidi.Tracks[2].Events.OfType <OnNoteVoiceMidiEvent>().Last().Note;

            //Midi should be flipped around the middle
            Assert.AreEqual(firstNote, lastFlippedNote);
            Assert.AreEqual(secondNote, thirdFlippedNote);
            Assert.AreEqual(thirdNote, secondFlippedNote);
            Assert.AreEqual(firstFlippedNote, lastNote);
        }
示例#2
0
        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Usage: SeparateTracks.exe filename.mid");
                Console.WriteLine("    filename.mid = MIDI file for which to generate code");
                Console.WriteLine();
                return;
            }

            if (!File.Exists(args[0]))
            {
                Console.WriteLine("Error: file {0} not found", args[0]);
                return;
            }

            try {
                MidiSequence sequence;
                using (Stream inputStream = File.OpenRead(args[0])) {
                    sequence = MidiSequence.Open(inputStream);
                }

                for (int i = 0; i < sequence.Tracks.Count; i++)
                {
                    MidiSequence newSequence = new MidiSequence(Format.Zero, sequence.Division);
                    newSequence.Tracks.Add(sequence.Tracks[i]);
                    using (Stream outputStream = File.OpenWrite(args[0] + "." + i + ".mid")) {
                        newSequence.Save(outputStream);
                    }
                }
            }
            catch (Exception exc) {
                Console.Error.WriteLine("Error: {0}", exc.Message);
            }
        }
示例#3
0
        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Usage: ExtractLyrics.exe filename.mid");
                Console.WriteLine("    filename.mid = MIDI file from which to extract lyric events text");
                Console.WriteLine();
                return;
            }

            if (!File.Exists(args[0]))
            {
                Console.WriteLine("Error: file {0} not found", args[0]);
                return;
            }

            try {
                MidiSequence sequence;
                using (Stream inputStream = File.OpenRead(args[0])) {
                    sequence = MidiSequence.Open(inputStream);
                }

                string[] lyrics = sequence.SelectMany(track => track.Events).OfType <LyricTextMetaMidiEvent>().Select(e => e.Text.Trim()).ToArray();
                Console.WriteLine(lyrics.Length > 0 ?
                                  string.Join(" ", lyrics) :
                                  "(no lyrics found)");
            }
            catch (Exception exc) {
                Console.Error.WriteLine("Error: {0}", exc.Message);
            }
        }
示例#4
0
        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Usage: GenerateMidiCode.exe filename.mid");
                Console.WriteLine("    filename.mid = MIDI file for which to generate code");
                Console.WriteLine();
                return;
            }

            if (!File.Exists(args[0]))
            {
                Console.WriteLine("Error: file {0} not found", args[0]);
                return;
            }

            try {
                MidiSequence sequence;
                using (Stream inputStream = File.OpenRead(args[0])) {
                    sequence = MidiSequence.Open(inputStream);
                }
                CSharpCodeGenerator.Write(sequence, "GeneratedCode", "Example", Console.Out);
            }
            catch (Exception exc) {
                Console.Error.WriteLine("Error: {0}", exc.Message);
            }
        }
示例#5
0
        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Usage: DumpMidi.exe filename.mid");
                Console.WriteLine("    filename.mid = MIDI file from which to extract lyric events text");
                Console.WriteLine();
                return;
            }

            if (!File.Exists(args[0]))
            {
                Console.WriteLine("Error: file {0} not found", args[0]);
                return;
            }

            try {
                using (Stream inputStream = File.OpenRead(args[0])) {
                    Console.WriteLine(MidiSequence.Open(inputStream));
                }
            }
            catch (Exception exc) {
                Console.Error.WriteLine("Error: {0}", exc.Message);
            }
        }
示例#6
0
        private void RoundtripEventsCore(MidiSequence seq1)
        {
            string tmpPath = Utils.SaveToTempFile(seq1);

            using (var s = File.OpenRead(tmpPath)) {
                Utils.AssertAreEqual(seq1, MidiSequence.Open(s));
            }
            File.Delete(tmpPath);
        }
示例#7
0
        public static void StrawberryPiano()
        {
            //File.WriteAllText("StrawberryPiano.bat", $"ffmpeg.exe -framerate 25 -i {Path.GetFullPath("StrawberryPianoFrames")}/frame*.png -r 25   -pix_fmt yuv420p out.mp4");

            var folder = @"C:\Users\alexm\Downloads";

            HashSet <byte> pressed = new HashSet <byte>();

            using (var f = new FileStream(@$ "{ folder}\Strawberry Piano.mid", FileMode.Open)) {
                var m = MidiSequence.Open(f);
                List <NoteVoiceMidiEvent> notes = new List <NoteVoiceMidiEvent>();
                foreach (var t in m.Tracks)
                {
                    notes.AddRange(t.Events.OfType <NoteVoiceMidiEvent>());
                }
                {
                    //Convert to absolute time
                    long previous = 0;
                    foreach (var n in notes)
                    {
                        var dt = n.DeltaTime;
                        n.DeltaTime = (dt + previous) / 30;
                        previous   += dt;
                    }
                    Console.WriteLine($"Note count: {notes.Count} ");
                    Console.WriteLine($"Last note: {notes.Last().DeltaTime} ms");
                    Console.WriteLine($"Last note: {notes.Last().DeltaTime / 1000} seconds");
                }
                var dir = @$ "{folder}\Strawberry Piano Frames";
                Directory.CreateDirectory(dir);

                int frameRate = 25;
                Console.WriteLine($"Frames: {notes.Last().DeltaTime * frameRate / 1000} frames");
                using (StrawberryVisualizer v = new StrawberryVisualizer(@$ "Strawberry Piano Note.png", $"StrawberryPianoFrames")) {
                    KeyTracker keys = new KeyTracker();

                    int index = 0;
                    int i     = 0;
                    while (index < notes.Count)
                    {
                        double time = i * 1000 / frameRate;
                        i++;
                        var now = notes.Skip(index).TakeWhile(n => n.DeltaTime <= time);
                        keys.Process(now);
                        index += now.Count();
                        v.AddFrame(keys.pressed);
                        //Console.WriteLine($"Time: {time}");
                        //Console.WriteLine($"Index: {index}");
                    }


                    Process.Start(Path.GetFullPath("StrawberryPiano.bat"));
                }
            }
示例#8
0
 private void importMIDIToolStripMenuItem_Click(object sender, EventArgs e)
 {
     try
     {
         fileSelector.Title = "Open MIDI file";
         fileSelector.ShowDialog();
         var myfile = fileSelector.FileName;
         var b      = File.OpenRead(myfile);
         currentSequence = MidiSequence.Open(b);
     } catch (Exception E)
     {
         Console.WriteLine("heck\n{0}", E.ToString());
         MessageBox.Show("Not a valid midi file.");
     }
 }
示例#9
0
        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Console.WriteLine("Usage: TransposeMidi.exe filename.mid steps");
                Console.WriteLine("    filename.mid = MIDI file to be transposed");
                Console.WriteLine("    steps = Number of steps to transpose, positive or negative");
                Console.WriteLine();
                return;
            }

            if (!File.Exists(args[0]))
            {
                Console.WriteLine("Error: file {0} not found", args[0]);
                return;
            }

            int steps;

            if (!int.TryParse(args[1], out steps))
            {
                Console.WriteLine("Error: invalid number of steps {0}", args[1]);
                return;
            }

            try
            {
                MidiSequence sequence;
                using (Stream inputStream = File.OpenRead(args[0]))
                {
                    sequence = MidiSequence.Open(inputStream);
                }

                sequence.Transpose(steps);

                string outputPath = args[0] + ".transposed.mid";
                using (Stream outputStream = File.OpenWrite(outputPath))
                {
                    sequence.Save(outputStream);
                }
                Console.WriteLine("Transposed MIDI written to: {0}", outputPath);
            }
            catch (Exception exc)
            {
                Console.Error.WriteLine("Error: {0}", exc.Message);
            }
        }
示例#10
0
            public static MidiSequence LoadMidiFile(string fileName)
            {
                MidiSequence sequence = null;

                try
                {
                    using (Stream inputStream = File.OpenRead(fileName))
                    {
                        sequence = MidiSequence.Open(inputStream);
                    }
                }
                catch (Exception exc)
                {
                    Debug.LogError("Error: " + exc.Message);
                }

                return(sequence);
            }
示例#11
0
        public void Flip_Should_Lower_Octave_When_Flipping_Above_127()
        {
            //Arrange
            MidiService target     = new MidiService();
            Stream      midiStream = File.Open($"{TestFilesPath}out_of_range_127.mid", FileMode.Open);
            const int   firstNote  = 127;
            const int   lastNote   = 115;

            //Act
            Stream flippedMidiStream = target.Flip(midiStream, 0);

            //Assert
            MidiSequence flippedMidi      = MidiSequence.Open(flippedMidiStream);
            int          firstFlippedNote = flippedMidi.Tracks[2].Events.OfType <OnNoteVoiceMidiEvent>().First().Note;
            int          lastFlippedNote  = flippedMidi.Tracks[2].Events.OfType <OnNoteVoiceMidiEvent>().Last().Note;

            //Midi should be flipped while also having been lowered by one octave
            Assert.AreEqual(firstNote, lastFlippedNote);
            Assert.AreEqual(firstFlippedNote, lastNote);
        }
示例#12
0
        public void LoadMIDI(string path)
        {
            try
            {
                using (System.IO.Stream inputStream = System.IO.File.OpenRead(path))
                {
                    sequence = MidiSequence.Open(inputStream);
                }

                var lbl = (Label)GetNode("SC/Label");
                lbl.Text = (string)sequence.ToString();

                Stop(); //Stop the player and clear the channels.

                //Set the MIDI sequence for the player.
                player.sequence = sequence;
                Clock.Reset(sequence.Tracks.Count); //RESET THE CLOCK.  This properly sets the number of tracks for the clock to check.

                AudioStreamGenerator streamGenerator = (AudioStreamGenerator)player.Stream;
                player.parser.ParseSequence(sequence, streamGenerator.MixRate);
            } catch (MidiParser.MidiParserException e) {
                GD.Print("WARNING:  Encountered a problem parsing MIDI.\n", e.ToString());
            }
        }
示例#13
0
        public IActionResult UploadFile()
        {
            try
            {
                var    file        = Request.Form.Files[0];
                string folderName  = "Upload";
                string webRootPath = "C:/";
                string newPath     = Path.Combine(webRootPath, folderName);
                if (!Directory.Exists(newPath))
                {
                    Directory.CreateDirectory(newPath);
                }
                if (file.Length > 0)
                {
                    string fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
                    string fullPath = Path.Combine(newPath, fileName);
                    using (var stream = new FileStream(fullPath, FileMode.Create))
                    {
                        file.CopyTo(stream);
                    }
                    MidiSequence sequence;
                    using (Stream inputStream = System.IO.File.OpenRead(fullPath))
                    {
                        sequence = MidiSequence.Open(inputStream);
                    }

                    int index = -1;
                    for (int i = 0; i < sequence.Tracks.Count && index == -1; i++)
                    {
                        for (int j = 0; j < sequence.Tracks[i].Events.Count; j++)
                        {
                            if (sequence.Tracks[i].Events[j].ToString().Contains("0x51"))
                            {
                                index = i;
                            }
                        }
                    }

                    if (index > 0)
                    {
                        foreach (MidiEvent Event in sequence.Tracks[0].Events)
                        {
                            if (Event.ToString().Contains("0x2F"))
                            {
                                sequence.Tracks[0].Events.Remove(Event);
                                break;
                            }
                        }
                        sequence.Tracks[0].Events.AddRange(sequence.Tracks[index].Events);
                        sequence.Tracks.Remove(sequence.Tracks[index]);
                    }

                    using (Stream outputStream = System.IO.File.OpenWrite(fullPath))
                    {
                        sequence.Save(outputStream);
                    }
                    FileStream fs = new FileStream(fullPath, FileMode.Open);
                    return(File(fs, "application/vnd.android.package-archive", fileName));
                }
                return(null);
            }
            catch (System.Exception ex)
            {
                return(null);
            }
        }
示例#14
0
        static void Main(string[] args)
        {
            double        toneDistance = 1;
            double        beatDistance = 1;
            double        n;
            List <string> lines = new List <string>();

            lines.Add("INSERT PUNCHHOLE");
            string path;
            double note;
            double ticks;
            double time;

            if (args.Length == 0)
            {
                Console.WriteLine("Usage: WintergatanLaserMIDI <filename.mid> [Tone Distance (mm)] [Beat Distance (mm)]");
                Console.WriteLine("\tfilename.mid = MIDI file for which to generate code");
                Console.WriteLine("\tTone Distance = Defines the distance between every note-pitch.");
                Console.WriteLine("\tBeat Distance = Defines how far away the beats are from each other.");
                Console.WriteLine();
                return;
            }

            if (!File.Exists(args[0]))
            {
                Console.WriteLine("Error: file {0} not found", args[0]);
                return;
            }

            path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase) + "\\" + args[0] + ".scr";
            path = new Uri(path).LocalPath;

            if (File.Exists(path))
            {
                File.Delete(path);
            }

            if (args.Length == 2 && !string.IsNullOrEmpty(args[1]))
            {
                if (double.TryParse(args[1], out n))
                {
                    toneDistance = n;
                }
                else
                {
                    Console.WriteLine("Tone Distance must be a number!");
                    return;
                }
            }

            if (args.Length == 3 && !string.IsNullOrEmpty(args[2]))
            {
                if (double.TryParse(args[2], out n))
                {
                    beatDistance = n;
                }
                else
                {
                    Console.WriteLine("Beat Distance must be a number!");
                    return;
                }
            }

            try
            {
                MidiSequence sequence = MidiSequence.Open(File.OpenRead(args[0]));
                ticks = (double)sequence.Division;

                foreach (MidiTrack track in sequence)
                {
                    track.Events.ConvertDeltasToTotals();
                    foreach (MidiEvent ev in track.Events)
                    {
                        if (ev.GetType().ToString() == "MidiSharp.Events.Voice.Note.OnNoteVoiceMidiEvent")
                        {
                            NoteVoiceMidiEvent nvme = ev as NoteVoiceMidiEvent;
                            note = (double)nvme.Note;
                            time = (double)ev.DeltaTime;

                            Console.WriteLine(((time / ticks) * beatDistance) + "," + ((note - 60.0d) * toneDistance));
                            if (lines.Count >= 2)
                            {
                                lines.Add("  " + ((time / ticks) * beatDistance) + "," + ((note - 60.0d) * toneDistance) + ",0 1 1 0");
                            }
                            else
                            {
                                lines.Add(((time / ticks) * beatDistance) + "," + ((note - 60.0d) * toneDistance) + ",0 1 1 0");
                            }
                        }
                    }
                }

                System.IO.File.WriteAllLines(path, lines);
            }
            catch (Exception exc)
            {
                Console.Error.WriteLine("Error: {0}", exc.Message);
            }
        }
示例#15
0
        static void Main(string[] args)
        {
            int[] codeMidi = new int[] { 0, 0, 0, 0, 0, 0, 0 };
            if (args.Length != 1)
            {
                Console.WriteLine("Usage: TransposeMidi.exe filename.mid steps");
                Console.WriteLine("    filename.mid = MIDI file to be transposed");
                Console.WriteLine("    steps = Number of steps to transpose, positive or negative");
                Console.WriteLine();
                return;
            }

            string originpath = System.IO.Directory.GetCurrentDirectory();

            string[] op = originpath.Split('\\');
            originpath = "";
            for (int i = 0; i < (op.Length) - 4; i++)
            {
                originpath += op[i];
                originpath += "\\";
            }



            if (!File.Exists(args[0]))
            {
                Console.WriteLine("Error: file {0} not found", args[0]);
                return;
            }

            /*            int steps;
             *          if (!int.TryParse(args[1], out steps))
             *          {
             *              Console.WriteLine("Error: invalid number of steps {0}", args[1]);
             *              return;
             *          }*/

            try
            {
                MidiSequence sequence;
                using (Stream inputStream = File.OpenRead(args[0]))
                {
                    sequence = MidiSequence.Open(inputStream);
                }



                for (int i = 0; i < 8; i++)
                {
                    MidiSequence newSequence = sequence.Trim(1857 * i, 1857 * (i + 1) + 10);
                    //              sequence.Transpose(steps);

                    using (Stream outputStream = File.OpenWrite(originpath + @"\\toUnity\\" + i + "\\" + "originmelody." + i + ".trimed.mid.txt"))
                    {
                        newSequence.Save(outputStream);
                    }
                    foreach (MidiTrack track in newSequence)
                    {
                        for (int j = 1; j < track.Events.Count - 1; j = j + 2)
                        {
                            //Console.WriteLine(track.Events[i].ToString().IndexOf("G4"));
                            //Console.WriteLine(track.Events[i].ToString());
                            //Console.WriteLine(track.Events[i].ToString().Substring(5,7));

                            char     spt      = '\t';
                            string[] spstring = track.Events[j].ToString().Split(spt);

                            switch (spstring[2])
                            {
                            case "C6": codeMidi[2] = codeMidi[2] + 3; codeMidi[5] = codeMidi[5] + 2; codeMidi[0]++; break;

                            case "D6": codeMidi[3] = codeMidi[3] + 3; codeMidi[6] = codeMidi[6] + 2; codeMidi[1]++; break;

                            case "E6": codeMidi[4] = codeMidi[4] + 3; codeMidi[0] = codeMidi[0] + 2; codeMidi[2]++; break;

                            case "F6": codeMidi[5] = codeMidi[5] + 3; codeMidi[1] = codeMidi[1] + 2; codeMidi[3]++; break;

                            case "G6": codeMidi[6] = codeMidi[6] + 3; codeMidi[2] = codeMidi[2] + 2; codeMidi[4]++; break;

                            case "A6": codeMidi[0] = codeMidi[0] + 3; codeMidi[5] = codeMidi[5] + 2; codeMidi[3]++; break;

                            case "B6": codeMidi[1] = codeMidi[1] + 3; codeMidi[6] = codeMidi[5] + 2; codeMidi[4]++; break;

                            default: break;
                            }

                            //Console.WriteLine(spstring[2]);
                        }
                        int maxValue = codeMidi.Max();

                        String        path    = System.IO.Directory.GetCurrentDirectory() + @"\\toUnity\\" + i;
                        DirectoryInfo dirInfo = new DirectoryInfo(path);
                        if (dirInfo.Exists == false)
                        {
                            Directory.CreateDirectory(path);
                        }

                        for (int j = 0; j < 8; j++)
                        {
                            if (codeMidi[j] == maxValue)
                            {
                                //Console.WriteLine(j);

                                List <String> MyFiles = Directory.GetFiles(originpath + @"\Resources\\" + j).ToList();

                                foreach (string file in MyFiles)
                                {
                                    FileInfo mFile = new FileInfo(file);
                                    // to remove name collisions
                                    if (new FileInfo(originpath + @"\\toUnity\\" + i + "\\" + mFile.Name).Exists == false)
                                    {
                                        mFile.CopyTo(originpath + @"\\toUnity\\" + i + "\\" + mFile.Name + ".txt");
                                    }
                                }
                                MyFiles.Clear();
                                MyFiles = null;
                                break;
                            }
                        }
                        System.Array.Clear(codeMidi, 0, 7);
                    }
                }
            }



            /*string outputPath = args[0] + ".transposed.mid";
             * using (Stream outputStream = File.OpenWrite(outputPath)) {
             *  sequence.Save(outputStream);
             * }
             * Console.WriteLine("Transposed MIDI written to: {0}", outputPath);*/
            //

            catch (Exception exc)
            {
                Console.Error.WriteLine("Error: {0}", exc.Message);
            }
        }
示例#16
0
        public MidiInterpretation(Stream midiStream, INoteSegmentProvider noteSegmentProvider)
        {
            MidiFile = MidiSequence.Open(midiStream);

            TempoCollection = new TempoCollection(MidiFile.TicksPerBeatOrFrame);

            NoteSegments = new List <NoteSegment>();

            // Calculate the absolute times for all events in each track
            // Also pair note on events with note off events
            for (int track = 0; track < MidiFile.Tracks.Count; track++)
            {
                // Key is a tuple of Channel and Note
                var onEvents = new Dictionary <(byte Channel, int Note), Queue <MidiEventWithTime <OnNoteVoiceMidiEvent> > >();

                // Time in ticks
                long time = 0;
                foreach (var midiEvent in MidiFile.Tracks[track].Events)
                {
                    if (midiEvent.DeltaTime > 0)
                    {
                        time += midiEvent.DeltaTime;
                    }

                    if (midiEvent is TempoMetaMidiEvent tempoEvent)
                    {
                        TempoCollection.AddTempoEvent(time, tempoEvent);
                    }
                    else if (midiEvent is OnNoteVoiceMidiEvent onNote)
                    {
                        var onNoteIdentifier = (onNote.Channel, onNote.Note);

                        if (!onEvents.ContainsKey(onNoteIdentifier))
                        {
                            onEvents[onNoteIdentifier] = new Queue <MidiEventWithTime <OnNoteVoiceMidiEvent> >();
                        }

                        // If the Velocity is 0, we are turning off a note using another OnNote (see https://stackoverflow.com/a/43322203/1984712)
                        // Basically, if a NoteOn event is received with a velocity of 0, we effectively have a NoteOff event.
                        if (onNote.Velocity == 0)
                        {
                            if (onEvents.TryGetValue(onNoteIdentifier, out var midiEventQueue))
                            {
                                NoteSegments.Add(noteSegmentProvider.CreateNoteSegment(
                                                     TempoCollection,
                                                     track,
                                                     midiEventQueue.Dequeue(), // Get the first matching On Event that matches this identifier
                                                     new MidiEventWithTime <OffNoteVoiceMidiEvent>(time, CreateOffNoteFromOnNote(onNote))
                                                     ));
                            }
                            else
                            {
                                System.Diagnostics.Debug.WriteLine(string.Format("OnNote event with Velocity = 0 at [ Channel: {0}; Note: {1} ] is missing a corresponding OnNote event with Velocity > 0.", onNoteIdentifier.Channel, onNoteIdentifier.Note));
                            }
                        }
                        // Otherwise, queue the note so that an OffNote can match to it
                        else
                        {
                            onEvents[onNoteIdentifier].Enqueue(new MidiEventWithTime <OnNoteVoiceMidiEvent>(time, onNote));
                        }
                    }
                    else if (midiEvent is OffNoteVoiceMidiEvent offNote)
                    {
                        var offNoteIdentifer = (offNote.Channel, offNote.Note);

                        if (onEvents.TryGetValue(offNoteIdentifer, out var midiEventQueue))
                        {
                            NoteSegments.Add(noteSegmentProvider.CreateNoteSegment(
                                                 TempoCollection,
                                                 track,
                                                 midiEventQueue.Dequeue(), // Get the first matching On Event
                                                 new MidiEventWithTime <OffNoteVoiceMidiEvent>(time, offNote))
                                             );
                        }
                        else
                        {
                            System.Diagnostics.Debug.WriteLine(string.Format("OffNote event at [ Channel: {0}; Note: {1} ] is missing a corresponding OnNote event.", offNoteIdentifer.Channel, offNoteIdentifer.Note));
                        }
                    }
                }

                if (onEvents.Any(e => e.Value.Count > 0))
                {
                    System.Diagnostics.Debug.WriteLine("One or more OnNote events weren't paired with an OffNote event.");
                }
            }

            TotalDurationSamples = NoteSegments.Max(segment => segment.StartSample + segment.DurationSamples);
        }
示例#17
0
        public Stream Flip(Stream midiFile, int octaveChangeOption)
        {
            //Load midi file
            MidiSequence midi = MidiSequence.Open(midiFile);

            //The anchor note to flip everything else around
            float anchorNote = midi.Tracks
                               .Where(t => t.Events.OfType <NoteVoiceMidiEvent>().Any() && t.Events.OfType <NoteVoiceMidiEvent>().Any(n => n.Channel != 9 && n.Channel != 10))
                               .Select(t => t.Events.OfType <NoteVoiceMidiEvent>().First())
                               .OrderBy(e => e.DeltaTime).GroupBy(e => e.DeltaTime).First() //Find the first note
                               .Min(e => e.Note);                                           //Order by note number if there are notes playing at the same time

            int highestNote = midi.Tracks
                              .Where(t => t.Events.OfType <NoteVoiceMidiEvent>().Any(n => n.Channel != 9 && n.Channel != 10))
                              .SelectMany(t => t.Events.OfType <NoteVoiceMidiEvent>())
                              .Max(e => e.Note);
            int lowestNote = midi.Tracks
                             .Where(t => t.Events.OfType <NoteVoiceMidiEvent>().Any(n => n.Channel != 9 && n.Channel != 10))
                             .SelectMany(t => t.Events.OfType <NoteVoiceMidiEvent>())
                             .Min(e => e.Note);

            int octaveChange = 0; //Global octave change required for this sequence

            octaveChangeOption *= Constants.Octave;

            bool flipFromMiddle = false; //If octave changes aren't possible, sequence needs to be flipped around the middle

            //Check if flipping won't make the notes go out of range (0-127) TODO: Test all cases
            if (anchorNote - lowestNote > highestNote - anchorNote)
            {
                //Flipping might make notes go past 127, if so, try to decrease octave
                float outOfRange = anchorNote + (anchorNote - lowestNote);

                if (outOfRange > Constants.MaxMidiNote)
                {
                    while (outOfRange + octaveChange > Constants.MaxMidiNote)
                    {
                        octaveChange -= Constants.Octave;
                    }

                    if (lowestNote + octaveChange < Constants.MinMidiNote)
                    {
                        //Out of range on the other side now, flip everything around the middle note instead and don't change octave
                        flipFromMiddle = true;
                        octaveChange   = 0;
                    }
                }
            }
            else
            {
                //Flipping might make notes go below 0, if so, try to increase octave
                float outOfRange = anchorNote - (highestNote - anchorNote);

                if (outOfRange < Constants.MinMidiNote)
                {
                    while (outOfRange + octaveChange < Constants.MinMidiNote)
                    {
                        octaveChange += Constants.Octave;
                    }

                    if (highestNote + octaveChange > Constants.MaxMidiNote)
                    {
                        //Out of range on the other side now, flip everything around the middle note instead and don't change octave
                        flipFromMiddle = true;
                        octaveChange   = 0;
                    }
                }
            }

            if (flipFromMiddle) //Changing octaves is not possible, flip everything around the middle
            {
                anchorNote = (float)(highestNote - lowestNote) / 2;
            }

            //Flip all notes
            foreach (MidiTrack track in midi.Tracks)
            {
                IEnumerable <NoteVoiceMidiEvent> noteEvents = track.OfType <NoteVoiceMidiEvent>().Where(n => n.Channel != 9 && n.Channel != 10);

                if (!noteEvents.Any())
                {
                    continue;                    //Nothing to flip
                }
                foreach (NoteVoiceMidiEvent onNoteEvent in noteEvents)
                {
                    onNoteEvent.Note = (byte)(anchorNote + anchorNote - onNoteEvent.Note + octaveChange + octaveChangeOption);
                }
            }

            //Create flipped MIDI-file
            Stream flippedMidiStream = new MemoryStream();

            midi.Save(flippedMidiStream);
            flippedMidiStream.Position = 0;

            return(flippedMidiStream);
        }