예제 #1
0
 public BeatTracker(BeatTracker tracker)
 {
     Interval       = tracker.Interval;
     NextPrediction = tracker.NextPrediction;
     ProcessedItems = new List <BeatEvent>(tracker.ProcessedItems);
     Rating         = tracker.Rating;
     OriginalScore  = tracker.OriginalScore;
 }
예제 #2
0
        static void Main(string[] args)
        {
            bool edit_only      = false;
            bool find_hierarchy = true;

            if (!edit_only)
            {
                MidiReader reader = new MidiReader();
                Console.WriteLine("Ready to record. Press any key to begin.");
                Console.ReadKey();

                reader.Start();
                Console.WriteLine("Recording started. Press any key to stop the recording.");
                Console.ReadKey();

                reader.Stop();
                Console.WriteLine("Recording finished. Processing...");
                List <BeatEvent>       beatEvents       = TempoInferrer.NotesToEvents(reader.FetchEventList());
                List <IntervalCluster> intervalClusters = TempoInferrer.EventsToClusters(beatEvents);
                intervalClusters = TempoInferrer.RateClusters(intervalClusters);
                BeatTracker     finalBeat = BeatInferrer.FindBeat(intervalClusters, beatEvents);
                RhythmStructure rhythm    = RhythmCreator.CreateRhythm(finalBeat, beatEvents);

                if (find_hierarchy)
                {
                    rhythm = HierarchicalRhythmInferrer.FindRepeatingUnit(rhythm);
                }

                AsciiTabRenderer.RenderAsciiTab(rhythm);

                Console.WriteLine("ASCII Tab rendered to tab.txt.");

                if (find_hierarchy)
                {
                    HierarchicalRhythm hRhythm = HierarchicalRhythmInferrer.CreateHierarchicalRhythm(rhythm);
                    hRhythm.Print();
                }
            }

            /* Read in (possibly edited) ASCII tab and convert to Sonic Pi */
            SonicPiEmitter.EmitSonicPi();

            Console.WriteLine("Sonic Pi code emitted to sonicpi.txt");

            Console.ReadKey();
        }
예제 #3
0
        /* Create a rhythm from a tracker and list of events, by quantizing the events
         * according to the beat tracker given to the function. */
        public static RhythmStructure CreateRhythm(BeatTracker tracker, List <BeatEvent> events)
        {
            const byte      numDivisions = 4;
            int             eventIndex   = 0;
            RhythmStructure rhythm       = new RhythmStructure(tracker.Interval);

            /* Iterate over all the beats and semiquavers, and set the semiquaver interval. */
            for (int i = 0; i < tracker.ProcessedItems.Count; i++)
            {
                BeatEvent baseEvent = tracker.ProcessedItems[i];
                double    interval;
                if (i != tracker.ProcessedItems.Count - 1)
                {
                    BeatEvent nextEvent = tracker.ProcessedItems[i + 1];
                    interval = (nextEvent.Time - baseEvent.Time) / 4;
                }
                else
                {
                    interval = (tracker.NextPrediction - baseEvent.Time) / 4;
                }

                for (int j = 0; j < numDivisions; j++)
                {
                    HashSet <Drum> drums = new HashSet <Drum>();

                    /* Determine the time at which one semiquaver event occurs and then quantizes each note event to the semiquaver. */
                    double baseTime = baseEvent.Time + (j * interval);
                    if (eventIndex < events.Count && baseTime - (interval / 2) < events[eventIndex].Time && baseTime + (interval / 2) > events[eventIndex].Time)
                    {
                        foreach (NoteEvent noteEvent in events[eventIndex].Notes)
                        {
                            if (indexToDrum.Keys.Contains(noteEvent.Channel))
                            {
                                Drum drum = indexToDrum[noteEvent.Channel];
                                drums.Add(drum);
                            }
                        }
                        eventIndex++;
                    }

                    rhythm.AddDrums(drums);
                }
            }

            return(rhythm);
        }
예제 #4
0
        public static BeatTracker FindBeat(List <IntervalCluster> tempoHypotheses, List <BeatEvent> events)
        {
            /* First, create all the trackers. */
            List <BeatTracker> trackers = new List <BeatTracker>();

            for (int i = 0; i < tempoHypotheses.Count; i++)
            {
                IntervalCluster cluster = tempoHypotheses[i];
                foreach (BeatEvent startEvent in events.Where(e => e.Time < initialPeriod).ToList())
                {
                    trackers.Add(new BeatTracker(cluster.MeanLength, startEvent, cluster.Rating));
                }
            }

            /* Iterate through every event in the rhythm, processing each tracker. */
            foreach (BeatEvent _event in events)
            {
                List <BeatTracker> newTrackers = new List <BeatTracker>();

                for (int i = trackers.Count - 1; i >= 0; i--)
                {
                    /* If any tracker has gone too long without detecting a beat candidate, drop it. */
                    BeatTracker tracker = trackers[i];
                    if (_event.Time - tracker.ProcessedItems[tracker.ProcessedItems.Count - 1].Time > maximumInterval)
                    {
                        trackers.RemoveAt(i);
                    }
                    else
                    {
                        /* Catch the trackers up with the current event. */
                        while (tracker.NextPrediction + (outerWindowFactor * tracker.Interval) < _event.Time)
                        {
                            tracker.NextPrediction += tracker.Interval;
                        }

                        /* Check whether the event is a feasible beat time. */
                        if (_event.Time > tracker.NextPrediction - (outerWindowFactor * tracker.Interval) &&
                            (_event.Time < tracker.NextPrediction + (outerWindowFactor * tracker.Interval)))
                        {
                            /* If it's too close to be sure, create another tracker. */
                            if (Math.Abs(_event.Time - tracker.NextPrediction) > innerWindow)
                            {
                                newTrackers.Add(new BeatTracker(tracker));
                            }

                            /* Update the tracker to prepare for the next loop iteration. */
                            double error = _event.Time - tracker.NextPrediction;
                            tracker.Interval      += error * correctionFactor;
                            tracker.NextPrediction = _event.Time + tracker.Interval;
                            tracker.ProcessedItems.Add(_event);

                            // NOTE: It might be useful to have drum specific stuff as well as velocity
                            tracker.Rating += (1 - (Math.Abs(error) / (2 * tracker.NextPrediction))) * _event.Notes.Sum(n => n.Velocity);
                        }
                    }
                }

                // Add new trackers to the list
                foreach (BeatTracker tracker in newTrackers)
                {
                    trackers.Add(tracker);
                }

                // Remove duplicate trackers
                List <BeatTracker> nextTrackers = new List <BeatTracker>();
                foreach (BeatTracker tracker in trackers)
                {
                    bool matchFound = false;
                    foreach (BeatTracker nextTracker in nextTrackers)
                    {
                        if (!matchFound && SimilarTrackers(tracker, nextTracker))
                        {
                            nextTracker.TakeBestTracker(tracker);
                            matchFound = true;
                        }
                    }

                    if (!matchFound)
                    {
                        nextTrackers.Add(tracker);
                    }
                }

                trackers = nextTrackers;
            }

            /* Weight each tracker's rating by the original score, so as to avoid very short beat selections. */
            foreach (BeatTracker tracker in trackers)
            {
                tracker.Rating *= tracker.OriginalScore;
            }

            trackers = trackers.OrderByDescending(t => t.Rating).ToList();

            // TODO: There are a lot of trackers that appear to be duplicates. Investigate.
            for (int i = 0; i < Math.Min(trackers.Count, 10); i++)
            {
                trackers[i].PrintTracker();
            }

            return(trackers[0]);
        }
예제 #5
0
 /* Fuzzy comparison of trackers, since they can be non-identical but functionally the same. */
 static bool SimilarTrackers(BeatTracker first, BeatTracker second)
 {
     return((Math.Abs(first.Interval - second.Interval) < 10) && (Math.Abs(first.NextPrediction - second.NextPrediction) < 20));
 }