( // ~distance is a function that expects two triads as arguments and calculates // the euclidian distance between them. In other words, it considers both // triads as points in a three-dimensional space. ~distance = { arg tr1, tr2; // Given two triads tr1=[a, b, c] and tr2=[x, y, z], the euclidian distance is // defined as // dist(tr1, tr2) = sqrt((a-x)² + (b-y)² + (c-z)²) // In sclang, we can use (tr2-tr1).sum({|i| i**2}).sqrt(); }; // ~findBestInversion expects two triads as argument and returns an inversion // of the second triad that has the minimal distance to the first in terms of // steps in the voices. ~findBestInversion = { arg tr1, tr2; // triads given. // Let's generate an array of all inversions of the second triad. We // will later find and return the one with the minimal distance. var inversions = [ tr2, // root position (tr2 + [0 , -12, -12]).sort, // first inversion, down an octave (tr2 + [0 , 0, -12]).sort, // second inversion, down an octave tr2 - 12, // root position, down an octave ]; // For each chord in the array `inversions` we calculate its ~distance // to the first triad and collect the results into an array. var distances = inversions.collect({|chord| ~distance.value(tr1, chord)}); // Find the index that contains the minimal distance. var minIdx = distances.minIndex; // Return the inversion at that index as our choice for the progression. inversions[minIdx]; }; // Test it on C-major → e-minor. Should return the first inversion, i.e. [-1, 4, 7]. ~findBestInversion.value([0,4,7], [4,7,11]) )