New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

tonal-pitchset

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tonal-pitchset - npm Package Compare versions

Comparing version 0.68.0 to 0.68.1

180

build/index.js

@@ -5,182 +5,30 @@ 'use strict';

var tonalPitch = require('tonal-pitch');
var tonalNote = require('tonal-note');
var tonalArray = require('tonal-array');
var tonalTranspose = require('tonal-transpose');
function toInt (set) { return parseInt(chroma(set), 2) }
function pitchChr (p) { p = tonalPitch.asPitch(p); return p ? tonalPitch.chr(p) : null }
/**
* Given a list of notes, return the notes of the pitchset
* starting with the first note of the list
*/
function notes (notes) {
var pcs = tonalArray.map(tonalNote.pc, notes)
if (!pcs.length) return pcs
var tonic = pcs[0]
// since the first note of the chroma is always C, we have to rotate it
var rotated = tonalArray.rotate(pitchChr(tonic), chroma(pcs).split('')).join('')
return fromChroma(rotated, tonic)
}
/**
* Given a pitch set (a list of notes or a pitch set chroma), produce the 12 rotations
* of the chroma (and discard the ones that starts with '0')
* Functions to create and manipulate pitch sets
*
* This can be used, for example, to get all the modes of a scale.
* @example
* var pitchset = require('tonal-pitchset')
*
* @param {Array|String} set - the list of notes or pitchChr of the set
* @param {Boolean} normalize - (Optional, true by default) remove all
* the rotations that starts with '0'
* @return {Array<String>} an array with all the modes of the chroma
*
* @example
* @module pitchset
*/
function chromaModes (set, normalize) {
normalize = normalize !== false
var binary = chroma(set).split('')
return tonalArray.compact(binary.map(function (_, i) {
var r = tonalArray.rotate(i, binary)
return normalize && r[0] === '0' ? null : r.join('')
}))
}
var REGEX = /^[01]{12}$/
/**
* Test if the given string is a pitch set chroma.
* @param {String} chroma - the pitch set chroma
* @return {Boolean} true if its a valid pitchset chroma
* @example
* pitchset.isChroma('101010101010') // => true
* pitchset.isChroma('101001') // => false
*/
function isChroma (set) {
return REGEX.test(set)
}
/**
* Get chroma of a pitch set. A chroma identifies each pitch set uniquely.
* It's a 12-digit binary each presenting one semitone of the octave.
* Get the notes of a pitch set. The notes in the set are sorted in asceding
* pitch order, and no repetitions are allowed.
*
* Note that this function accepts a chroma as parameter and return it
* without modification.
* Note that it creates pitch sets and NOT picth class sets. This functionallity
* resides inside `tonal-pcset` module.
*
* @param {Array|String} set - the pitch set
* @return {String} a binary representation of the pitch set
* @param {String|Array} notes - the notes to create the pitch set from
* @return {Array<String>} the ordered pitch set notes
* @example
* pitchset.chroma('C D E') // => '1010100000000'
* pitchset.notes('C4 c3 C5 c4') // => ['C3', 'C4', 'C5']
*/
function chroma (set) {
if (isChroma(set)) return set
var b = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
tonalArray.map(pitchChr, set).forEach(function (i) {
b[i] = 1
function notes (notes) {
return tonalArray.sort(notes).filter(function (n, i, arr) {
return i === 0 || n !== arr[i - 1]
})
return b.join('')
}
var IVLS = '1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M'.split(' ')
/**
* Given a pitch set in binary notation it returns the intervals or notes
* (depending on the tonic)
* @param {String} binary - the pitch set in binary representation
* @param {String|Pitch} tonic - the pitch set tonic
* @return {Array} a list of notes or intervals
* @example
* pitchset.fromChroma('101010101010', 'C') // => ['C', 'D', 'E', 'Gb', 'Ab', 'Bb']
*/
function fromChroma (binary, tonic) {
if (arguments.length === 1) return function (t) { return fromChroma(binary, t) }
if (!isChroma(binary)) return null
tonic = tonic || 'P1'
return tonalArray.compact(binary.split('').map(function (d, i) {
return d === '1' ? tonalTranspose.transpose(IVLS[i], tonic) : null
}))
}
/**
* Test if two pitch sets are identical
*
* @param {Array|String} set1 - one of the pitch sets
* @param {Array|String} set2 - the other pitch set
* @return {Boolean} true if they are equal
* @example
* pitchset.equal('c2 d3', 'c5 d2') // => true
*/
function equal (s1, s2) {
if (arguments.length === 1) return function (s) { return equal(s1, s) }
return chroma(s1) === chroma(s2)
}
/**
* Test if a pitch set is a subset of another
*
* @param {Array|String} set - the base set to test against
* @param {Array|String} test - the set to test
* @return {Boolean} true if the test set is a subset of the set
* @example
* pitchset.subset('c d e', 'C2 D4 D5 C6') // => true
*/
function subset (set, test) {
if (arguments.length === 1) return function (t) { return subset(set, t) }
test = toInt(test)
return (test & toInt(set)) === test
}
/**
* Test if a pitch set is a superset
* @param {Array|String} set - the base set to test against
* @param {Array|String} test - the set to test
* @return {Boolean} true if the test set is a superset of the set
* @example
* pitchset.subset('c d e', 'C2 D4 F4 D5 E5 C6') // => true
*/
function superset (set, test) {
if (arguments.length === 1) return function (t) { return superset(set, t) }
test = toInt(test)
return (test | toInt(set)) === test
}
/**
* Test if a given pitch set includes a note
* @param {Array|String} set - the base set to test against
* @param {String|Pitch} note - the note to test
* @return {Boolean} true if the note is included in the pitchset
* @example
* pitchset.includes('c d e', 'C4') // =A true
* pitchset.includes('c d e', 'C#4') // =A false
*/
function includes (set, note) {
if (arguments.length > 1) return includes(set)(note)
set = chroma(set)
return function (note) { return set[pitchChr(note)] === '1' }
}
/**
* Filter a list with a pitch set
*
* @param {Array|String} set - the pitch set
* @param {Array|String} notes - the note list to be filtered
* @return {Array} the filtered notes
*
* @example
* pitchset.filter('c d e', 'c2 c#2 d2 c3 c#3 d3') // => [ 'c2', 'd2', 'c3', 'd3' ])
*/
function filter (set, notes) {
if (arguments.length === 1) return function (n) { return filter(set, n) }
return tonalArray.asArr(notes).filter(includes(set))
}
exports.notes = notes;
exports.chromaModes = chromaModes;
exports.isChroma = isChroma;
exports.chroma = chroma;
exports.fromChroma = fromChroma;
exports.equal = equal;
exports.subset = subset;
exports.superset = superset;
exports.includes = includes;
exports.filter = filter;

@@ -6,176 +6,23 @@ /**

* var pitchset = require('tonal-pitchset')
* pitchset.equal('c2 d5 e6', 'c6 e3 d1') // => true
*
* @module pitchset
*/
import { chr, asPitch } from 'tonal-pitch'
import { pc } from 'tonal-note'
import { map, asArr, rotate, compact } from 'tonal-array'
import { transpose } from 'tonal-transpose'
import { sort } from 'tonal-array'
function toInt (set) { return parseInt(chroma(set), 2) }
function pitchChr (p) { p = asPitch(p); return p ? chr(p) : null }
/**
* Given a list of notes, return the notes of the pitchset
* starting with the first note of the list
*/
export function notes (notes) {
var pcs = map(pc, notes)
if (!pcs.length) return pcs
var tonic = pcs[0]
// since the first note of the chroma is always C, we have to rotate it
var rotated = rotate(pitchChr(tonic), chroma(pcs).split('')).join('')
return fromChroma(rotated, tonic)
}
/**
* Given a pitch set (a list of notes or a pitch set chroma), produce the 12 rotations
* of the chroma (and discard the ones that starts with '0')
* Get the notes of a pitch set. The notes in the set are sorted in asceding
* pitch order, and no repetitions are allowed.
*
* This can be used, for example, to get all the modes of a scale.
* Note that it creates pitch sets and NOT picth class sets. This functionallity
* resides inside `tonal-pcset` module.
*
* @param {Array|String} set - the list of notes or pitchChr of the set
* @param {Boolean} normalize - (Optional, true by default) remove all
* the rotations that starts with '0'
* @return {Array<String>} an array with all the modes of the chroma
*
* @param {String|Array} notes - the notes to create the pitch set from
* @return {Array<String>} the ordered pitch set notes
* @example
* pitchset.chromaModes('C E G')
* pitchset.notes('C4 c3 C5 c4') // => ['C3', 'C4', 'C5']
*/
export function chromaModes (set, normalize) {
normalize = normalize !== false
var binary = chroma(set).split('')
return compact(binary.map(function (_, i) {
var r = rotate(i, binary)
return normalize && r[0] === '0' ? null : r.join('')
}))
}
var REGEX = /^[01]{12}$/
/**
* Test if the given string is a pitch set chroma.
* @param {String} chroma - the pitch set chroma
* @return {Boolean} true if its a valid pitchset chroma
* @example
* pitchset.isChroma('101010101010') // => true
* pitchset.isChroma('101001') // => false
*/
export function isChroma (set) {
return REGEX.test(set)
}
/**
* Get chroma of a pitch set. A chroma identifies each pitch set uniquely.
* It's a 12-digit binary each presenting one semitone of the octave.
*
* Note that this function accepts a chroma as parameter and return it
* without modification.
*
* @param {Array|String} set - the pitch set
* @return {String} a binary representation of the pitch set
* @example
* pitchset.chroma('C D E') // => '1010100000000'
*/
export function chroma (set) {
if (isChroma(set)) return set
var b = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
map(pitchChr, set).forEach(function (i) {
b[i] = 1
export function notes (notes) {
return sort(notes).filter(function (n, i, arr) {
return i === 0 || n !== arr[i - 1]
})
return b.join('')
}
var IVLS = '1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M'.split(' ')
/**
* Given a pitch set in binary notation it returns the intervals or notes
* (depending on the tonic)
* @param {String} binary - the pitch set in binary representation
* @param {String|Pitch} tonic - the pitch set tonic
* @return {Array} a list of notes or intervals
* @example
* pitchset.fromChroma('101010101010', 'C') // => ['C', 'D', 'E', 'Gb', 'Ab', 'Bb']
*/
export function fromChroma (binary, tonic) {
if (arguments.length === 1) return function (t) { return fromChroma(binary, t) }
if (!isChroma(binary)) return null
tonic = tonic || 'P1'
return compact(binary.split('').map(function (d, i) {
return d === '1' ? transpose(IVLS[i], tonic) : null
}))
}
/**
* Test if two pitch sets are identical
*
* @param {Array|String} set1 - one of the pitch sets
* @param {Array|String} set2 - the other pitch set
* @return {Boolean} true if they are equal
* @example
* pitchset.equal('c2 d3', 'c5 d2') // => true
*/
export function equal (s1, s2) {
if (arguments.length === 1) return function (s) { return equal(s1, s) }
return chroma(s1) === chroma(s2)
}
/**
* Test if a pitch set is a subset of another
*
* @param {Array|String} set - the base set to test against
* @param {Array|String} test - the set to test
* @return {Boolean} true if the test set is a subset of the set
* @example
* pitchset.subset('c d e', 'C2 D4 D5 C6') // => true
*/
export function subset (set, test) {
if (arguments.length === 1) return function (t) { return subset(set, t) }
test = toInt(test)
return (test & toInt(set)) === test
}
/**
* Test if a pitch set is a superset
* @param {Array|String} set - the base set to test against
* @param {Array|String} test - the set to test
* @return {Boolean} true if the test set is a superset of the set
* @example
* pitchset.subset('c d e', 'C2 D4 F4 D5 E5 C6') // => true
*/
export function superset (set, test) {
if (arguments.length === 1) return function (t) { return superset(set, t) }
test = toInt(test)
return (test | toInt(set)) === test
}
/**
* Test if a given pitch set includes a note
* @param {Array|String} set - the base set to test against
* @param {String|Pitch} note - the note to test
* @return {Boolean} true if the note is included in the pitchset
* @example
* pitchset.includes('c d e', 'C4') // =A true
* pitchset.includes('c d e', 'C#4') // =A false
*/
export function includes (set, note) {
if (arguments.length > 1) return includes(set)(note)
set = chroma(set)
return function (note) { return set[pitchChr(note)] === '1' }
}
/**
* Filter a list with a pitch set
*
* @param {Array|String} set - the pitch set
* @param {Array|String} notes - the note list to be filtered
* @return {Array} the filtered notes
*
* @example
* pitchset.filter('c d e', 'c2 c#2 d2 c3 c#3 d3') // => [ 'c2', 'd2', 'c3', 'd3' ])
*/
export function filter (set, notes) {
if (arguments.length === 1) return function (n) { return filter(set, n) }
return asArr(notes).filter(includes(set))
}

2

package.json
{
"name": "tonal-pitchset",
"version": "0.68.0",
"version": "0.68.1",
"description": "Pitch set utilities",

@@ -5,0 +5,0 @@ "keywords": [],

@@ -5,88 +5,4 @@ var test = require('tape')

test('pitchset: notes', function (t) {
t.deepEqual(pitchset.notes('g4 f5 g3 d3 a3 a4 c6 a1'),
[ 'G', 'A', 'C', 'D', 'F' ])
t.deepEqual(pitchset.notes('C4 c3 C5 C4 c4'), ['C3', 'C4', 'C5'])
t.end()
})
test('pitchset: chroma', function (t) {
t.equal(pitchset.chroma('c d e'), '101010000000')
t.equal(pitchset.chroma('g g#4 a bb5'), '000000011110')
t.equal(pitchset.chroma('P1 M2 M3 P4 P5 M6 M7'),
pitchset.chroma('c d e f g a b'))
t.equal(pitchset.chroma('101010101010'), '101010101010')
t.end()
})
test('pitchset: fromChroma', function (t) {
t.deepEqual(pitchset.fromChroma('101010101010', 'C'),
[ 'C', 'D', 'E', 'Gb', 'Ab', 'Bb' ])
t.deepEqual(pitchset.fromChroma('101010101010', null),
[ '1P', '2M', '3M', '5d', '6m', '7m' ])
t.end()
})
test('pitchset: modes', function (t) {
// TODO: fixme, the 4th mode should have F# instead of Gb
t.deepEqual(pitchset.chromaModes('c d e f g a b').map(function (chroma, i) {
return pitchset.fromChroma(chroma, 'C')
}), [ [ 'C', 'D', 'E', 'F', 'G', 'A', 'B' ],
[ 'C', 'D', 'Eb', 'F', 'G', 'A', 'Bb' ],
[ 'C', 'Db', 'Eb', 'F', 'G', 'Ab', 'Bb' ],
[ 'C', 'D', 'E', 'Gb', 'G', 'A', 'B' ],
[ 'C', 'D', 'E', 'F', 'G', 'A', 'Bb' ],
[ 'C', 'D', 'Eb', 'F', 'G', 'Ab', 'Bb' ],
[ 'C', 'Db', 'Eb', 'F', 'Gb', 'Ab', 'Bb' ] ])
t.end()
})
test('pitchset: isChroma', function (t) {
t.equal(pitchset.isChroma('101010101010'), true)
t.equal(pitchset.isChroma('1010101'), false)
t.equal(pitchset.isChroma('blah'), false)
t.equal(pitchset.isChroma('c d e'), false)
t.end()
})
test('pitchset: subset', function (t) {
t.equal(pitchset.subset('c4 d5 e6', 'c2 d3'), true)
t.equal(pitchset.subset('c4 d5 e6', 'c2 d3 e5'), true)
t.equal(pitchset.subset('c d e', 'c d e f'), false)
t.equal(pitchset.subset('c d e', 'c2 d3 f6'), false)
t.end()
})
test('pitchset: superset', function (t) {
t.equal(pitchset.superset('c d e', 'c2 d3 e4 f5'), true)
t.equal(pitchset.superset('c d e', 'e f g'), false)
t.equal(pitchset.superset('c d e', 'd e'), false)
t.end()
})
test('pitchset: equal', function (t) {
t.ok(pitchset.equal('c2 d3 e7 f5', 'c4 c d5 e6 f1'))
t.end()
})
test('pitchset: includes', function (t) {
t.equal(pitchset.includes('c d e', 'C4'), true)
t.equal(pitchset.includes('c d e', 'C#4'), false)
t.end()
})
test('pitchset: filter', function (t) {
t.deepEqual(pitchset.filter('c d e', 'c2 c#2 d2 c3 c#3 d3'),
[ 'c2', 'd2', 'c3', 'd3' ])
t.end()
})
test('pitchset: chromaModes', function (t) {
t.deepEqual(pitchset.chromaModes('c d e f g a b'),
[ '101011010101', '101101010110', '110101011010', '101010110101',
'101011010110', '101101011010', '110101101010' ])
t.deepEqual(pitchset.chromaModes('c d e f g a b', false),
[ '101011010101', '010110101011', '101101010110', '011010101101',
'110101011010', '101010110101', '010101101011', '101011010110',
'010110101101', '101101011010', '011010110101', '110101101010' ])
t.deepEqual(pitchset.chromaModes('blah bleh'), [])
t.end()
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc