예제 #1
0
 public void Play(double durationMS, double frequency, float volume)
 {
     started  = GetUnixTime();
     duration = durationMS;
     if (debugMode)
     {
         new Beep((int)frequency, (int)duration, volume).Play();
     }
     else
     {
         OpenVRHelper.PlayNote(controller, (float)durationMS / 1000F, (float)frequency, volume);
     }
 }
예제 #2
0
        static void Run(Settings settings)
        {
            if (!OpenVRHelper.InitHMD() && !settings.Debug)
            {
                return;
            }

            Console.WriteLine("Found {0} devices", OpenVRHelper.DeviceCount());

            string inputFile = settings.InputFile;

            if (!File.Exists(inputFile))
            {
                Console.WriteLine("Input file {0} doesn't exist!", inputFile);
                return;
            }

            MidiFile midi = new MidiFile(inputFile, false);

            Console.WriteLine("Found {0} devices", OpenVRHelper.DeviceCount());

            Player[] players = new Player[OpenVRHelper.DeviceCount()];
            for (int i = 0; i < players.Count(); i++)
            {
                players[i] = new Player(i, settings.Tolerance, settings.Debug);
            }

            //these will bet set correctly before any notes are played
            double bpm             = 120;
            double ticksPerQuarter = 1;
            double msPerQuarter    = 1;

            int divison = midi.DeltaTicksPerQuarterNote;

            int[]     trackEventIndex = new int[midi.Events.Count()];
            long      currentTick     = 0;
            Stopwatch sw            = Stopwatch.StartNew();
            int       tracksStopped = 0;

            //based on https://github.com/ipatix/serialmidi/blob/master/serialmidi/Program.cs
            //and https://gitlab.com/Pilatomic/SteamControllerSinger/blob/master/main.cpp
            while (true)
            {
                for (int trackNum = 0; trackNum < midi.Events.Count(); trackNum++)
                {
                    var track = midi.Events[trackNum];
                    if (trackEventIndex[trackNum] >= track.Count())
                    {
                        continue;
                    }

                    while (currentTick >= track[trackEventIndex[trackNum]].AbsoluteTime)
                    {
                        var ev = track[trackEventIndex[trackNum]];
                        if (ev.CommandCode == MidiCommandCode.NoteOn)
                        {
                            NoteOnEvent note = (NoteOnEvent)ev;
                            if (note.OffEvent == null)
                            {
                                Console.WriteLine("Note {0} doesn't have an off event, skipping.", note.NoteName);
                            }
                            else
                            {
                                //calculate note duration
                                double duration = note.NoteLength * msPerQuarter;

                                //calculate frequency from the note number
                                //https://pages.mtu.edu/~suits/NoteFreqCalcs.html
                                double frequency = (440F * Math.Pow(2, (note.NoteNumber - 69) / 12F));

                                for (int i = 0; i < players.Count(); i++)
                                {
                                    if (players[i].IsBusy())
                                    {
                                        if (i == players.Count() - 1)
                                        {
                                            Console.WriteLine("Note {0} can't be played because both controllers are busy. Consider changing this part of the song or increasing tolerance time (-t).", note.NoteName);
                                        }
                                        continue;
                                    }
                                    Console.WriteLine("Controller {0}: note {1} ({2:0.##} Hz) for {3:0.##} ms", i, note.NoteName, frequency, duration);
                                    players[i].Play(duration, frequency, settings.Volume);
                                    break;
                                }
                            }
                        }
                        if (ev.CommandCode == MidiCommandCode.MetaEvent)
                        {
                            MetaEvent meta = (MetaEvent)ev;
                            if (meta.MetaEventType == MetaEventType.SetTempo)
                            {
                                TempoEvent tempoEvent = (TempoEvent)meta;
                                bpm = tempoEvent.Tempo;
                                if (settings.Debug)
                                {
                                    Console.WriteLine("New tempo: " + bpm + " BPM");
                                }
                                //https://stackoverflow.com/questions/2038313/converting-midi-ticks-to-actual-playback-seconds
                                ticksPerQuarter = (60 * Stopwatch.Frequency) / (bpm * divison);
                                msPerQuarter    = (60000F / (bpm * divison));
                            }
                        }
                        trackEventIndex[trackNum]++;
                        if (trackEventIndex[trackNum] == track.Count)
                        {
                            tracksStopped++;
                            if (settings.Debug)
                            {
                                Console.WriteLine("Stopped track {0}/{1}", tracksStopped, midi.Events.Count());
                            }
                            break;
                        }
                    }
                }
                if (tracksStopped == midi.Events.Count())
                {
                    break;
                }

                currentTick++;

                //just skip cycles for now
                while (sw.ElapsedTicks < ticksPerQuarter)
                {
                    ;
                }
                sw.Restart();
            }
            sw.Stop();

            Console.WriteLine("Stopped");
            OpenVRHelper.Shutdown();
        }