/// <summary> /// Generates a list of chords by pulling the live cells from the underlying TokenGroup with the current NoteGroup parameters. /// </summary> private void InitChordsFromTokenGroup() { Chords = new List<Chord>(); // Grab all of the cells from the token group that are within the specified left and right bounds. // Then, sort them so that notes played first are nearest to the zero index. // Need to find the pop index of the farthest right cell for use with the set right bound. int rightmostPop = _tokenGroup.Cells.Max(x => x[0]); List<int[]> validCells = new List<int[]>(_tokenGroup.Cells.Where(x => x[0] >= _leftBound && x[0] < rightmostPop-_rightBound)); validCells.Sort((cell1, cell2) => cell1[0].CompareTo(cell2[0])); // Iterate through the cells, joining cells w/ the same population index into the same Chord, adding them to the Chord list. // Set the beginning beat & duration of each chord/note as appropriate to the beat # of the song, by the parameters set for this NG. // Also, "shift" cells over by the first cell[0] so that groups modified by the left bound will still start on beat 0. // ALSO, skip the first n notes the first time through, where n is the value of the Horizontal Offset. double currentTotalBeat = 0; // The actual beat counter for the song. Chord currentChord = new Chord(new List<Note>(), 0); // The first chord of every NG starst at beat 0. if (validCells.Count == 0) return; List<int[]> horizOffsetCells = new List<int[]>(); if (HorizOffset > 0) { int startRangeIndex = HorizOffset%validCells.Count; horizOffsetCells.AddRange(validCells.GetRange(startRangeIndex, validCells.Count - startRangeIndex)); validCells.RemoveRange(startRangeIndex, validCells.Count - startRangeIndex); } float cellOffset = validCells[0][0]; // Keep going until we've added enough chords for the duration of the entire "song". while (currentTotalBeat < SongDuration) { double currentPatternBeat = 0; // The current beat in a single run-through of the pattern. foreach (int[] cell in validCells) { // Adjust the start beat of the note by the left bounds, so the pattern starts at beat zero. float startBeat = (cell[0] - cellOffset); // If we're finished with the current chord, make a new one. if (startBeat*_noteDuration > currentPatternBeat) { currentPatternBeat = startBeat*_noteDuration; // Go directly to jail. Do not pass Go, do not collect $200. if (currentTotalBeat + currentPatternBeat > SongDuration) return; Chords.Add(new Chord(currentChord.Notes, currentChord.StartBeat)); currentChord = new Chord(new List<Note>(), (float)(currentPatternBeat+currentTotalBeat)); // Note: I hope this cast doesn't bite me in the ass. } // Add a new note to the chord with the correct pitch, duration, and on the correct beat. Adjust the pitch by the vertical shift, wrapping // around if necessary. // Also add the "current" beat to it to allow for repitition if this isn't the first time through the while loop. currentChord.Notes.Add(new Note(_scale[Utilities.Mod(cell[1] + _vertOffset, _scale.Length)], _noteDuration, currentPatternBeat+currentTotalBeat)); } // Add that last chord to the song, since we're repeating. Chords.Add(new Chord(currentChord.Notes, currentChord.StartBeat)); // NOTE: Deadly copypasta // We've made a full pass through the cells of the TokenGroup, so add on the repetition delay to the current beat, and go back to see if we should // cycle back through the cells again. currentTotalBeat += currentPatternBeat + _noteDuration + _repetitionInterval; currentChord = new Chord(new List<Note>(), (float)currentTotalBeat); // Set the next chord to be made to the current total beat if (horizOffsetCells.Count != 0) { validCells.InsertRange(0, horizOffsetCells); horizOffsetCells.Clear(); } } }
private void PlayChord(Chord chord) { // Spawn a new thread to play each note. This way the notes in a chord don't all have to have the same duration. for (int i = 0; i < chord.Notes.Count; i++) { Note note = chord.Notes[i]; _sineWaveProviders[(int)note.Pitch].Amplitude = _defaultPitchAmp; _notesBeingPlayed.Add(new PlayedNote(note, _currentBeat + note.Duration)); //Console.WriteLine("On" + " " + _pitchUsageCounters[(int)note.Pitch]); } // Console.WriteLine(DateTime.Now); //Console.WriteLine("\n"); }