Exemple #1
0
        static int RunDebug(DebugOptions options)
        {
            var engine = new DesktopEngine();

            var midiAccess = MidiAccessManager.Default;

            Console.WriteLine("MIDI Inputs");
            Console.WriteLine("-----------");
            Console.WriteLine("");
            Console.WriteLine($"\tId\tName");
            Console.WriteLine($"-----------------------------------");
            foreach (var input in midiAccess.Inputs)
            {
                Console.WriteLine($"\t{input.Id}\t{input.Name}");
            }

            Console.WriteLine();

            Console.WriteLine("MIDI Outputs");
            Console.WriteLine("------------");
            Console.WriteLine("");
            Console.WriteLine($"\tId\tName");
            Console.WriteLine($"-----------------------------------");
            foreach (var output in midiAccess.Outputs)
            {
                Console.WriteLine($"\t{output.Id}\t{output.Name}");
            }

            return(0);
        }
Exemple #2
0
        static int RunPlay(PlayOptions options)
        {
            var engine = new DesktopEngine();

            engine.Server.Run(engine);

            return(0);
        }
Exemple #3
0
        static int RunPlayDirect(PlayDirectOptions options)
        {
            var engine = new DesktopEngine();

            var midiAccess = MidiAccessManager.Default;

            foreach (var input in options.MidiInputs)
            {
                var foundMidiInput = midiAccess.Inputs.Where(x => x.Name.ToLower().Contains(input.ToLower()) || x.Id.ToLower().Contains(input.ToLower())).FirstOrDefault();

                if (foundMidiInput == null)
                {
                    Console.Error.WriteLine($"Did not find any MIDI input partially matching '{input}'.");
                    return(1);
                }
                else
                {
                    Console.WriteLine($"Using MIDI input '{foundMidiInput.Name}'.");
                }
                engine.MidiInputs.Add(midiAccess.OpenInputAsync(foundMidiInput.Id).Result);
            }

            foreach (var output in options.MidiOutputs)
            {
                var foundMidiOutput = midiAccess.Outputs.Where(x => x.Name.ToLower().Contains(output.ToLower()) || x.Id.ToLower().Contains(output.ToLower())).FirstOrDefault();

                if (foundMidiOutput == null)
                {
                    Console.Error.WriteLine($"Did not find any MIDI output partially matching '{output}'.");
                    return(1);
                }
                else
                {
                    Console.WriteLine($"Using MIDI output'{foundMidiOutput.Name}'.");
                }
                engine.MidiOutputs.Add(midiAccess.OpenOutputAsync(foundMidiOutput.Id).Result);
            }

            var scoreFilePath = options.FilePath;

            FileStream fileStream = null;

            ScoreBuilder            scoreBuilder    = null;
            Score                   score           = null;
            Dictionary <byte, byte> noteVelocityMap = new Dictionary <byte, byte>();

            foreach (var index in Enumerable.Range(0, 128))
            {
                noteVelocityMap.Add((byte)index, 0);
            }
            var lastNoteOnVelocities = new Queue <decimal>(3);

            if (scoreFilePath != null)
            {
                if (!File.Exists(options.FilePath))
                {
                    Console.Error.WriteLine($"Could not find sheet music file '{options.FilePath}'.");
                    return(1);
                }

                try
                {
                    fileStream = new FileStream(scoreFilePath, FileMode.Open);
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine($"Could not open sheet music file path {scoreFilePath}: {ex}");
                }

                if (fileStream == null)
                {
                    return(2);
                }

                try
                {
                    scoreBuilder = new ScoreBuilder(fileStream);
                    score        = scoreBuilder.Build();
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine($"Could not build sheet music score from file path {scoreFilePath}: {ex}");
                }

                if (scoreBuilder == null || score == null)
                {
                    return(3);
                }
                else
                {
                    Console.WriteLine($"Successfully loaded sheet music at {scoreFilePath}.");
                }

                engine.Interpreter.SetScore(score, scoreFilePath);
            }

            foreach (var midiInput in engine.MidiInputs)
            {
                midiInput.MessageReceived += (object sender, MidiReceivedEventArgs e) =>
                {
                    switch (e.Data[0])
                    {
                    case MidiEvent.NoteOff:
                    {
                        var pitch = e.Data[1];
                        Console.WriteLine($"Off (actual): {pitch}");
                        engine.Interpreter.Input(new NoteRelease()
                            {
                                Pitch = pitch
                            });
                    }
                    break;

                    case MidiEvent.NoteOn:
                    {
                        var pitch    = e.Data[1];
                        var velocity = e.Data[2];

                        var isSimulatedNoteOff = velocity == 0;
                        var isRequestedPitchAlreadyAtZeroVelocity = noteVelocityMap[pitch] == 0;
                        var isRequestedNoteOffAlreadyNoteOff      = isRequestedPitchAlreadyAtZeroVelocity;
                        var shouldNoteOffBeNoteOn = isSimulatedNoteOff && isRequestedNoteOffAlreadyNoteOff;

                        if (shouldNoteOffBeNoteOn)
                        {
                            var averagePreviousNoteVelocities = (byte)(lastNoteOnVelocities.Average());
                            Console.WriteLine($"<!!! CAUGHT !!!> On (simulated) {counter1++}: {pitch} at {String.Format("{0:0%}", averagePreviousNoteVelocities / 127.0)}");
                            noteVelocityMap[pitch] = averagePreviousNoteVelocities;
                            engine.Interpreter.Input(new NotePress()
                                {
                                    Pitch    = pitch,
                                    Velocity = averagePreviousNoteVelocities
                                });
                        }
                        else
                        {
                            /** The Yamaha P-45 sends Note Off messages as Note On
                             * messages with zero velocity. */
                            var isNoteOnActuallyNoteOff = velocity == 0;

                            if (isNoteOnActuallyNoteOff)
                            {
                                Console.WriteLine($"Off (simulated) {counter1++}: {pitch} at {String.Format("{0:0%}", velocity / 127.0)} <---> (Last) {String.Format("{0:0%}", (byte)noteVelocityMap[pitch] / 127.0)}");
                                noteVelocityMap[pitch] = 0;
                                engine.Interpreter.Input(new NoteRelease()
                                    {
                                        Pitch = pitch
                                    });
                            }
                            else
                            {
                                lastNoteOnVelocities.Enqueue(velocity);
                                if (lastNoteOnVelocities.Count > 3)
                                {
                                    lastNoteOnVelocities.Dequeue();
                                }

                                noteVelocityMap[pitch] = velocity;
                                Console.WriteLine($"On {counter1++}: {pitch} at {String.Format("{0:0%}", velocity / 127.0)}");
                                engine.Interpreter.Input(new NotePress()
                                    {
                                        Pitch    = pitch,
                                        Velocity = velocity
                                    });
                            }
                        }
                    }
                    break;

                    case MidiEvent.CC:
                    {
                        var pedalKind = e.Data[1];
                        var position  = (byte)(127 - e.Data[2]);

                        // Console.WriteLine($"Pedal {counter1++}: {String.Format("{0:0%}", position / 127.0)}");
                        engine.Interpreter.Input(new PedalChange()
                            {
                                Pedal    = PedalKind.Sustain,
                                Position = position
                            });
                    }
                    break;
                    }
                };
            }

            engine.Interpreter.Output += (IPianoEvent e) =>
            {
                foreach (var output in engine.MidiOutputs)
                {
                    switch (e)
                    {
                    case PedalChange pedal:
                        output.Send(new byte[]
                        {
                            MidiEvent.CC,
                            pedal.Pedal switch
                            {
                                PedalKind.UnaCorda => 67,
                                PedalKind.Sostenuto => 66,
                                PedalKind.Sustain => 64,
                                _ => 64
                            },
                            (byte)(pedal.Position)
                        }, 0, 3, 0);
                        break;