Exemple #1
0
        /* This function strips down a rhythm into its smallest repeating unit as a power of two semiquavers. */
        public static RhythmStructure FindRepeatingUnit(RhythmStructure rhythm)
        {
            int             rhythmLength           = rhythm.drums.Count;
            int             maxRepeatingUnitLength = 4 * (rhythmLength / 4);
            bool            repeatingUnitFound     = false;
            int             unitLength             = 4;
            RhythmStructure rhythmUnit             = new RhythmStructure(rhythm.beatInterval);

            /* Basically, start with a unit of length one and check it against the rest of the rhythm,
             * if it doesn't match keep doubling the length until it matches, or take the original rhythm. */
            while (!repeatingUnitFound && unitLength <= maxRepeatingUnitLength)
            {
                rhythmUnit = rhythm.CopySub(0, unitLength, rhythm.beatInterval);
                int repetitions = (rhythmLength / unitLength) - 1;
                repeatingUnitFound = true;

                for (int i = 0; i < repetitions; i++)
                {
                    if (!rhythm.CheckMatch(rhythmUnit, (i + 1) * unitLength))
                    {
                        repeatingUnitFound = false;
                    }
                }

                unitLength += 4;
            }

            return(rhythmUnit);
        }
Exemple #2
0
        public RhythmStructure CopySub(int startIndex, int length, double interval)
        {
            RhythmStructure copy = new RhythmStructure(interval);

            for (int i = startIndex; i < startIndex + length; i++)
            {
                copy.AddDrums(GetAtIndex(i));
            }

            return(copy);
        }
Exemple #3
0
        public static HierarchicalRhythm CreateHierarchicalRhythm(RhythmStructure rhythm)
        {
            RhythmStructure    rhythmCopy = new RhythmStructure(rhythm);
            int                treeDepth  = (int)Math.Log(rhythm.drums.Count, 2);
            HierarchicalRhythm hRhythm    = new HierarchicalRhythm(rhythm.beatInterval, treeDepth);

            foreach (Drum drum in drumList)
            {
                /* Tree level 0 is the root, for drums that occur on every semiquaver of the rhythm,
                 * and the bottom level is the notes that occur only once across the rhythm. */
                for (int level = 0; level <= treeDepth; level++)
                {
                    int intervalBetweenNotes = (int)Math.Pow(2, level);

                    /* This index is the amount that the recurring note is "shifted" across the rhythm.
                     * For example, if we're at minim level, then at i=3 we have notes occuring every minim,
                     * starting on the semiquaver with index 3. */
                    for (int shift = 0; shift < intervalBetweenNotes; shift++)
                    {
                        /* If the particular drum we're looking at is found in the rhythm,
                         * at the location we're dealing with, start scanning along. */
                        if (rhythmCopy.GetAtIndex(shift).Contains(drum))
                        {
                            /* Finally, iterate across the entire rhythm according to the shift and interval.
                             * TODO: This isn't very efficient, would be better to stop immediately if there's a mismatch. */
                            bool notesLineUp = true;

                            for (int i = shift; i < rhythmCopy.drums.Count; i += intervalBetweenNotes)
                            {
                                if (!rhythmCopy.GetAtIndex(i).Contains(drum))
                                {
                                    notesLineUp = false;
                                }
                            }

                            if (notesLineUp)
                            {
                                hRhythm.AddDrum(level, shift, drum);

                                for (int i = shift; i < rhythmCopy.drums.Count; i += intervalBetweenNotes)
                                {
                                    rhythmCopy.RemoveDrumAt(i, drum);
                                }
                            }
                        }
                    }
                }
            }

            return(hRhythm);
        }
Exemple #4
0
        // Check all of the input rhythm against the subsection of this rhythm given by the parameters.
        public bool CheckMatch(RhythmStructure otherRhythm, int startIndex)
        {
            bool match = true;

            for (int i = startIndex; i < startIndex + otherRhythm.drums.Count; i++)
            {
                int otherRhythmIndex = i - startIndex;
                if (!drums[i].SetEquals(otherRhythm.drums[otherRhythmIndex]))
                {
                    match = false;
                }
            }

            return(match);
        }
        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();
        }
        /* 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);
        }
        /* We render the ASCII tab based on the original rhythm. */
        public static void RenderAsciiTab(RhythmStructure rhythm)
        {
            Dictionary <string, string> tab = new Dictionary <string, string>();

            foreach (LabelSymbolPair pair in drumToName.Values)
            {
                tab[pair.label] = pair.label + "|";
            }

            /* Initialize each slot with the "-" symbol then replace it if we find any of the right drum during this interval. */
            for (int i = 0; i < rhythm.drums.Count; i++)
            {
                HashSet <Drum> drums = rhythm.drums[i];
                foreach (string index in tab.Keys.ToList())
                {
                    tab[index] += "-";
                }

                foreach (Drum drum in drums)
                {
                    if (drumToName.Keys.Contains(drum))
                    {
                        LabelSymbolPair pair = drumToName[drum];
                        tab[pair.label] = tab[pair.label].Remove(i + 3, 1).Insert(i + 3, pair.symbol);
                    }
                }
            }

            /* Finally write out the tab to a text file. */
            using (StreamWriter writer = new StreamWriter("tab.txt"))
            {
                writer.WriteLine(Convert.ToInt32(rhythm.beatInterval));
                foreach (string str in tab.Values)
                {
                    writer.WriteLine(str);
                }
            }
        }
Exemple #8
0
 // NOTE: This copy may need to go deeper as it copies hash set references.
 public RhythmStructure(RhythmStructure rhythm)
 {
     beatInterval = rhythm.beatInterval;
     drums        = new List <HashSet <Drum> >(rhythm.drums);
 }