Skip to content

Instantly share code, notes, and snippets.

@lerouxb
Created February 5, 2026 21:59
Show Gist options
  • Select an option

  • Save lerouxb/29b0a430aa6a57d447ca1cb43ee52c0e to your computer and use it in GitHub Desktop.

Select an option

Save lerouxb/29b0a430aa6a57d447ca1cb43ee52c0e to your computer and use it in GitHub Desktop.
/**
* Checks if two numbers are relatively prime (coprime).
* @param {number} k - The number of pulses.
* @param {number} n - The total number of steps.
* @returns {boolean} - True if GCD is 1, otherwise false.
*/
function areRelativelyPrime(k, n) {
// Helper function using the Euclidean Algorithm to find GCD
function gcd(a, b) {
while (b !== 0) {
let temp = b;
b = a % b;
a = temp;
}
return a;
}
// Two numbers are relatively prime if their GCD is 1
return gcd(k, n) === 1;
}
/**
* Generates a Euclidean rhythm pattern.
* @param {number} k - Number of pulses (onsets).
* @param {number} n - Total number of steps (length).
* @returns {number[]} Array of 1s and 0s representing the rhythm.
*/
function generateEuclidean(k, n) {
// 1. Initial state: k groups of [1] and n-k groups of [0]
let groups = [];
for (let i = 0; i < n; i++) {
groups.push(i < k ? [1] : [0]);
}
// 2. Iteratively distribute the remainder groups into the leading groups
let l = n - k; // Number of zeros initially
let m = k; // Number of ones initially
while (l > 0 && m > 0) {
let numToMove = Math.min(m, l);
for (let i = 0; i < numToMove; i++) {
// Concatenate the last group into the i-th group
groups[i] = groups[i].concat(groups.pop());
}
// Update counts based on what was moved
if (m > l) {
m = l;
l = m - l; // This logic follows the recursive Euclidean structure
} else {
l = l - m;
}
// Re-calculating remaining groups for the next iteration
m = numToMove;
l = groups.length - m;
// Exit when there is only one type of group left or no remainder
if (l <= 1) break;
}
// 3. Flatten the nested arrays into a single sequence
return groups.flat();
}
let total = 0;
console.log('std::vector<std::vector<std::bool>> euclideanRhythms {');
console.log(' // none');
console.log(' { 0 },');
console.log(' // four to the floor');
console.log(' { 1 },');
for (let n = 1; n <= 16; n++) {
for (let k = 1; k < n; k++) {
if (areRelativelyPrime(k, n)) {
const pattern = generateEuclidean(k, n);
console.log(` // k=${k}, n=${n}`);
console.log(` { ${pattern.join(', ')} },`);
total++;
}
}
}
console.log('};')
console.log(`Total: ${total}`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment