Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 4x 1x 1x 4x 24x 24x 24x 8x 16x 8x 1x 15x | import { A } from '@ember/array'; import { arraySwap, flatten } from './array-methods'; /** * @public * @class utils */ /** * Sorts an array of {{#crossLink "Note"}}Notes{{/crossLink}} so that they are in the same order that they would * appear on a piano. * * @param {array} notes An array of notes that should be musically-sorted. * * @public * @method sortNotes * * @return {array} Array of musically-sorted notes. */ export function sortNotes(notes) { // get octaves so that we can sort based on them let sortedNotes = extractOctaves(notes); // Each octave has tons of duplicates sortedNotes = stripDuplicateOctaves(sortedNotes); // Create array of arrays. Each inner array contains all the notes in an octave sortedNotes = createOctavesWithNotes(sortedNotes); // Sort the notes in each octave, alphabetically, flats before naturals sortedNotes = octaveSort(sortedNotes); // Determine last note of first octave, then for each octave, split at // that note, then shift the beginning notes to the end sortedNotes = octaveShift(sortedNotes); // Flatten array of arrays into a flat array return A(flatten(sortedNotes)); } /** * Takes an array of arrays of notes, determines the last note of * the first array, then splits the rest of the arrays in the array at the last * note of the first array, and moves the beginning of the array to the end * so that each array starts at the next note after the last note of the first * array, instead of at "A" (alphabetically). * * @example * This is hard to explain. Here's an example. * (Simplified, as the real notes are objects) * * Example input: [['A0', 'B0'], ['A1', 'B1', 'C1', 'D1']] * Example output: [['A0', 'B0'], ['C1', 'D1', 'A1', 'B1']] * * @private * @method octaveShift * * @param {array} octaves An array of octaves, each octave is an array of Notes. * * @return {array} Input array after having been shifted. */ export function octaveShift(octaves) { // Pull first octave from beginning of array const firstOctave = A(A(octaves).shiftObject()); // Get all the note names from the second octave for comparison const secondOctaveNames = A(octaves.get('firstObject')).getEach('name'); // Get the note name of the last note in the first octave const lastNote = firstOctave.get('lastObject.name'); // Get the index of the occurrence of the last note from the first // octave, in the second octave const indexToShiftAt = secondOctaveNames.lastIndexOf(lastNote) + 1; // Split the octave array at that point, and move the first chunk to the end return A(octaves.map((octave) => arraySwap(octave, indexToShiftAt))) // Put first octave back at the beginning of the array .unshiftObjects([firstOctave]); } /** * Maps through an array of arrays and sorts each array with * "noteSort" * * @private * @method octaveSort * * @param {array} octaves array of arrays to be sorted * * @return {array} array of sorted arrays */ export function octaveSort(octaves) { return octaves.map((octave) => octave.sort(noteSort)); } /** * Accepts an array of Note objects and passes back an array * like this: [original array, array of each octave in the orginal array] * * @private * @method extractOctaves * * @param {array} notes array of note objects. * * @return {array} array containing two inner arrays, [0] is the untouched input * array, [1] is an array of all the octaves in the original array. */ export function extractOctaves(notes) { return [ notes, A(A(notes).getEach('octave')) ]; } /** * Accepts an array of two arrays and returns the same * array, but with array at index [1] uniq'd and sorted alphabetically. * * @private * @method stripDuplicateOctaves * * @param {array} [ notes, octaves ] the output from extractOctaves. * * @return {array} The mutated array. */ export function stripDuplicateOctaves([ notes, octaves ]) { return [ notes, A(octaves).uniq().sort() ]; } /** * Accepts an array of two arrays, [0] being an array * of Note objects, [1] being all the available octaves. Returns a single array * made up of arrays of Note objects, organized by octave. Each inner array * represents all of the notes in an octave. * * @private * @method createOctavesWithNotes * * @param {array} data The output of stripDuplicateOctaves. * * @return {Ember.MutableArray} */ export function createOctavesWithNotes([ notes, octaves ]) { return A(octaves).map((octave) => A(notes).filterBy('octave', octave)); } /** * Acts as a comparator function for the * {{#crossLink "Array/sort:method"}}Array.prototype.sort{{/crossLink}} method. * Sorts two {{#crossLink "Note"}}{{/crossLink}} instances alphabetically, flats * before naturals. * * @private * @method noteSort * * @param {Note} a The first Note instance to compare. * @param {Note} b The second Note instance to compare. * * @return {number} -1 or 1, depending on whether the current * {{#crossLink "Note"}}{{/crossLink}} instance should be sorted left, or right. */ export function noteSort(a, b) { const aLet = a.get('letter'); const bLet = b.get('letter'); if (aLet < bLet) { return -1; } if (aLet === bLet) { if (a.get('accidental') === 'b') { return -1; } } return 1; } |