tonal-array
Advanced tools
Comparing version 0.50.4 to 0.50.5
@@ -212,2 +212,65 @@ 'use strict'; | ||
function trOct (n) { return tonalTranspose.tr(tonalPitch.pitch(0, n, 1)) } | ||
/** | ||
* Rotates a list a number of times. It's completly agnostic about the | ||
* contents of the list. | ||
* @param {Integer} times - the number of rotations | ||
* @param {Array|String} list - the list to be rotated | ||
* @return {Array} the rotated array | ||
*/ | ||
function rotate (times, list) { | ||
var arr = asArr(list) | ||
var len = arr.length | ||
var n = ((times % len) + len) % len | ||
return arr.slice(n, len).concat(arr.slice(0, n)) | ||
} | ||
/** | ||
* Rotates an ascending list of pitches n times keeping the ascending property. | ||
* This functions assumes the list is an ascending list of pitches, and | ||
* transposes the them to ensure they are ascending after rotation. | ||
* It can be used, for example, to invert chords. | ||
* | ||
* @param {Integer} times - the number of rotations | ||
* @param {Array|String} list - the list to be rotated | ||
* @return {Array} the rotated array | ||
*/ | ||
function rotateAsc (times, list) { | ||
return listFn(function (arr) { | ||
var len = arr.length | ||
var n = ((times % len) + len) % len | ||
var head = arr.slice(n, len) | ||
var tail = arr.slice(0, n) | ||
// See if the first note of tail is lower than the last of head | ||
var s = tonalDistance.distInSemitones(head[len - n - 1], tail[0]) | ||
if (s < 0) { | ||
var octs = Math.floor(s / 12) | ||
if (times < 0) head = head.map(trOct(octs)) | ||
else tail = tail.map(trOct(-octs)) | ||
} | ||
return head.concat(tail) | ||
})(list) | ||
} | ||
/** | ||
* Select elements from a list. | ||
* | ||
* @param {String|Array} numbers - a __1-based__ index of the elements | ||
* @param {String|Array} list - the list of pitches | ||
* @return {Array} the selected elements (with nulls if not valid index) | ||
* | ||
* @example | ||
* import { select } from 'tonal-array' | ||
* select('1 3 5', 'C D E F G A B') // => ['C', 'E', 'G'] | ||
* select('-1 0 1 2 3', 'C D') // => [ null, null, 'C', 'D', null ] | ||
*/ | ||
function select (nums, list) { | ||
if (arguments.length === 1) return function (l) { return select(nums, l) } | ||
var arr = asArr(list) | ||
return asArr(nums).map(function (n) { | ||
return arr[n - 1] || null | ||
}) | ||
} | ||
// #### Transform lists in array notation | ||
@@ -252,2 +315,5 @@ function asPitchStr (p) { return tonalPitch.strPitch(p) || p } | ||
exports.shuffle = shuffle; | ||
exports.rotate = rotate; | ||
exports.rotateAsc = rotateAsc; | ||
exports.select = select; | ||
exports.listFn = listFn; |
67
index.js
@@ -1,5 +0,5 @@ | ||
import { asPitch, isPitch, strPitch } from 'tonal-pitch' | ||
import { asPitch, isPitch, strPitch, pitch } from 'tonal-pitch' | ||
import { isArr, isNum } from 'tonal-notation' | ||
import { tr } from 'tonal-transpose' | ||
import { distance } from 'tonal-distance' | ||
import { distance, distInSemitones } from 'tonal-distance' | ||
function id (x) { return x } | ||
@@ -209,2 +209,65 @@ | ||
function trOct (n) { return tr(pitch(0, n, 1)) } | ||
/** | ||
* Rotates a list a number of times. It's completly agnostic about the | ||
* contents of the list. | ||
* @param {Integer} times - the number of rotations | ||
* @param {Array|String} list - the list to be rotated | ||
* @return {Array} the rotated array | ||
*/ | ||
export function rotate (times, list) { | ||
var arr = asArr(list) | ||
var len = arr.length | ||
var n = ((times % len) + len) % len | ||
return arr.slice(n, len).concat(arr.slice(0, n)) | ||
} | ||
/** | ||
* Rotates an ascending list of pitches n times keeping the ascending property. | ||
* This functions assumes the list is an ascending list of pitches, and | ||
* transposes the them to ensure they are ascending after rotation. | ||
* It can be used, for example, to invert chords. | ||
* | ||
* @param {Integer} times - the number of rotations | ||
* @param {Array|String} list - the list to be rotated | ||
* @return {Array} the rotated array | ||
*/ | ||
export function rotateAsc (times, list) { | ||
return listFn(function (arr) { | ||
var len = arr.length | ||
var n = ((times % len) + len) % len | ||
var head = arr.slice(n, len) | ||
var tail = arr.slice(0, n) | ||
// See if the first note of tail is lower than the last of head | ||
var s = distInSemitones(head[len - n - 1], tail[0]) | ||
if (s < 0) { | ||
var octs = Math.floor(s / 12) | ||
if (times < 0) head = head.map(trOct(octs)) | ||
else tail = tail.map(trOct(-octs)) | ||
} | ||
return head.concat(tail) | ||
})(list) | ||
} | ||
/** | ||
* Select elements from a list. | ||
* | ||
* @param {String|Array} numbers - a __1-based__ index of the elements | ||
* @param {String|Array} list - the list of pitches | ||
* @return {Array} the selected elements (with nulls if not valid index) | ||
* | ||
* @example | ||
* import { select } from 'tonal-array' | ||
* select('1 3 5', 'C D E F G A B') // => ['C', 'E', 'G'] | ||
* select('-1 0 1 2 3', 'C D') // => [ null, null, 'C', 'D', null ] | ||
*/ | ||
export function select (nums, list) { | ||
if (arguments.length === 1) return function (l) { return select(nums, l) } | ||
var arr = asArr(list) | ||
return asArr(nums).map(function (n) { | ||
return arr[n - 1] || null | ||
}) | ||
} | ||
// #### Transform lists in array notation | ||
@@ -211,0 +274,0 @@ function asPitchStr (p) { return strPitch(p) || p } |
{ | ||
"name": "tonal-array", | ||
"version": "0.50.4", | ||
"version": "0.50.5", | ||
"description": "Create and manipulate arrays of notes and intervals", | ||
@@ -25,3 +25,3 @@ "keywords": [ | ||
"dependencies": { | ||
"tonal-distance": "^0.50.1", | ||
"tonal-distance": "^0.50.2", | ||
"tonal-notation": "^0.50.0", | ||
@@ -28,0 +28,0 @@ "tonal-pitch": "^0.50.0", |
@@ -68,2 +68,15 @@ # tonal-array [![npm version](https://img.shields.io/npm/v/tonal-array.svg)](https://www.npmjs.com/package/tonal-array) | ||
</dd> | ||
<dt><a href="#rotate">rotate(times, list)</a> ⇒ <code>Array</code></dt> | ||
<dd><p>Rotates a list a number of times. It's completly agnostic about the | ||
contents of the list.</p> | ||
</dd> | ||
<dt><a href="#rotateAsc">rotateAsc(times, list)</a> ⇒ <code>Array</code></dt> | ||
<dd><p>Rotates an ascending list of pitches n times keeping the ascending property. | ||
This functions assumes the list is an ascending list of pitches, and | ||
transposes the them to ensure they are ascending after rotation. | ||
It can be used, for example, to invert chords.</p> | ||
</dd> | ||
<dt><a href="#select">select(numbers, list)</a> ⇒ <code>Array</code></dt> | ||
<dd><p>Select elements from a list.</p> | ||
</dd> | ||
<dt><a href="#listFn">listFn(fn)</a> ⇒ <code>function</code></dt> | ||
@@ -272,2 +285,51 @@ <dd><p>Decorates a function to so it's first parameter is an array of pitches in | ||
``` | ||
<a name="rotate"></a> | ||
## rotate(times, list) ⇒ <code>Array</code> | ||
Rotates a list a number of times. It's completly agnostic about the | ||
contents of the list. | ||
**Kind**: global function | ||
**Returns**: <code>Array</code> - the rotated array | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| times | <code>Integer</code> | the number of rotations | | ||
| list | <code>Array</code> | <code>String</code> | the list to be rotated | | ||
<a name="rotateAsc"></a> | ||
## rotateAsc(times, list) ⇒ <code>Array</code> | ||
Rotates an ascending list of pitches n times keeping the ascending property. | ||
This functions assumes the list is an ascending list of pitches, and | ||
transposes the them to ensure they are ascending after rotation. | ||
It can be used, for example, to invert chords. | ||
**Kind**: global function | ||
**Returns**: <code>Array</code> - the rotated array | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| times | <code>Integer</code> | the number of rotations | | ||
| list | <code>Array</code> | <code>String</code> | the list to be rotated | | ||
<a name="select"></a> | ||
## select(numbers, list) ⇒ <code>Array</code> | ||
Select elements from a list. | ||
**Kind**: global function | ||
**Returns**: <code>Array</code> - the selected elements (with nulls if not valid index) | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| numbers | <code>String</code> | <code>Array</code> | a __1-based__ index of the elements | | ||
| list | <code>String</code> | <code>Array</code> | the list of pitches | | ||
**Example** | ||
```js | ||
import { select } from 'tonal-array' | ||
select('1 3 5', 'C D E F G A B') // => ['C', 'E', 'G'] | ||
select('-1 0 1 2 3', 'C D') // => [ null, null, 'C', 'D', null ] | ||
``` | ||
<a name="listFn"></a> | ||
@@ -274,0 +336,0 @@ |
@@ -59,1 +59,30 @@ var test = require('tape') | ||
}) | ||
test('rotate', function (t) { | ||
t.deepEqual(_.rotate(1, 'c d e'), ['d', 'e', 'c']) | ||
t.deepEqual(_.rotate(-1, 'c d e'), [ 'e', 'c', 'd' ]) | ||
t.deepEqual(_.rotate(0, 'c d e'), [ 'c', 'd', 'e' ]) | ||
t.end() | ||
}) | ||
test('rotateAsc', function (t) { | ||
t.deepEqual(_.rotateAsc(1, 'c d e'), ['D', 'E', 'C']) | ||
t.deepEqual(_.rotateAsc(-1, 'c d e'), [ 'E', 'C', 'D' ]) | ||
t.deepEqual(_.rotateAsc(0, 'c d e'), [ 'C', 'D', 'E' ]) | ||
t.deepEqual(_.rotateAsc(1, 'c4 d4 e4'), [ 'D4', 'E4', 'C5' ]) | ||
t.deepEqual(_.rotateAsc(2, 'c4 d4 e4'), [ 'E4', 'C5', 'D5' ]) | ||
t.deepEqual(_.rotateAsc(-1, 'c4 d4 e4'), [ 'E3', 'C4', 'D4' ]) | ||
t.deepEqual(_.rotateAsc(-2, 'c4 d4 e4'), [ 'D3', 'E3', 'C4' ]) | ||
t.deepEqual(_.rotateAsc(1, 'C1 D3 E5'), [ 'D3', 'E5', 'C6' ]) | ||
t.deepEqual(_.rotateAsc(2, 'C1 D3 E5'), [ 'E5', 'C6', 'D8' ]) | ||
t.deepEqual(_.rotateAsc(-1, 'C1 D3 E5'), [ 'E0', 'C1', 'D3' ]) | ||
t.deepEqual(_.rotateAsc(-2, 'C1 D3 E5'), [ 'D-2', 'E0', 'C1' ]) | ||
t.end() | ||
}) | ||
test('select', function (t) { | ||
t.deepEqual(_.select('1 3 5', 'C D E F G A B'), ['C', 'E', 'G']) | ||
t.deepEqual(_.select('1 -3 12 4', 'C D E F G A B'), [ 'C', null, null, 'F' ]) | ||
t.deepEqual(_.select('-1 0 1 2 3', 'C D'), [ null, null, 'C', 'D', null ]) | ||
t.end() | ||
}) |
45653
7
649
353
Updatedtonal-distance@^0.50.2