Skip to content

Commit 9d7d9dd

Browse files
authored
Merge pull request #85 from nnirror/v1.4.1
V1.4.1
2 parents b188663 + 218111b commit 9d7d9dd

File tree

5 files changed

+215
-128
lines changed

5 files changed

+215
-128
lines changed

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,11 @@ You need to connect the MIDI device you want to use before starting Facet.
204204
- example:
205205
- `$('example').drunk(64,0.1).cc();`
206206
---
207-
- **chord** ( _chord_type_, _inversion_mode_ = 0 )
207+
- **chord** ( _chordTypePattern_, _inversion_mode_ = 0 )
208208
- creates a chord of MIDI notes for every value in the FacetPattern's data.
209-
- if the `chord_type` argument is a FacetPattern, the chord intervals will correspond to the data of the `chord_type` FacetPattern.
210-
- if `chord_type` is a string, it must be from the below list of chord names:
209+
- `chordTypePattern` can be a string, or a FacetPattern, or an array of either. If `chordTypePattern` is a FacetPattern, the chord intervals will correspond to the data of the `chordTypePattern` FacetPattern.
210+
- if `chordTypePattern` is an array with more than one value in it, then the chord type will change dynamically over the course of the loop. For example, a `chordTypePattern` of ['major','maj7','minor'] will produce major chords for the first third of the loop, then switch to maj7 chords for the middle third, then switch to minor chords for the last third.
211+
- if `chordTypePattern` is a string, it must be from the below list of chord names:
211212

212213
`maj` / `major` = `0,4,7`
213214

@@ -232,17 +233,18 @@ You need to connect the MIDI device you want to use before starting Facet.
232233
- example:
233234
- `$('example').ramp(36,72,32).chord('maj7').add((bars%4)*12).key('F#','major').note(50,100,1);`
234235
- `$('example').noise(16).scale(36,90).chord(_.from([3,5,7,10,11,14,16,20,25])).key('c','major').note(); // 9-note chords mapped onto c major`
236+
- `$('example').noise(8).scale(30,80).chord('maj7').key(['c','f#'], ['major','minor']).note(100,500); // maj7 chords, first in c major, then in f# minor`
235237
---
236-
- **key** ( _key_letter_, _key_scale_ )
237-
- translates a FacetPattern with data in the range of MIDI note numbers (0-127) so all its values now adhere to the supplied `key_letter` and `key_scale`.
238-
- `key_letter` values: "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"
239-
- `key_scale` values can either be a string (see list below) or a FacetPattern containing 1-12 binary numbers (see examples).
238+
- **key** ( _keyLetterPattern_, _keyScalePattern_ )
239+
- translates a FacetPattern with data in the range of MIDI note numbers (0-127) so all its values now adhere to the supplied `keyLetterPattern` and `keyScalePattern`.
240+
- `keyLetterPattern` values can be a string: "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", or an array, or strings: `["A", "D"]`, or a FacetPattern of strings: `_.from(['A','D']).dup(3).shuffle()`. When `keyLetterPattern` contains multiple values, the key will change dynamically over the course of the loop. So a `keyLetterPattern` of `["A", "D", "G"]` will be in the key of A for the first third, then switch to D for the middle third, then switch to G for the last third.
241+
- `keyScalePattern` values can either be a string (see list below), or a FacetPattern containing 1-12 binary numbers (see examples), or an array of strings/FacetPatterns, in which case the values change dynamically over the course of the loop.
240242
- possible scales: ["major pentatonic", "major", "minor", "major blues", "minor blues", "melodic minor", "harmonic minor", "bebop", "diminished", "dorian", "lydian", "mixolydian", "phrygian", "locrian", "ionian pentatonic", "mixolydian pentatonic", "ritusen", "egyptian", "neopolitan major pentatonic", "vietnamese 1", "pelog", "kumoijoshi", "hirajoshi", "iwato", "in-sen", "lydian pentatonic", "malkos raga", "locrian pentatonic", "minor pentatonic", "minor six pentatonic", "flat three pentatonic", "flat six pentatonic", "scriabin", "whole tone pentatonic", "lydian #5P pentatonic", "lydian dominant pentatonic", "minor #7M pentatonic", "super locrian pentatonic", "minor hexatonic", "augmented", "piongio", "prometheus neopolitan", "prometheus", "mystery #1", "six tone symmetric", "whole tone", "messiaen's mode #5", "locrian major", "double harmonic lydian", "altered", "locrian #2", "mixolydian b6", "lydian dominant", "lydian augmented", "dorian b2", "ultralocrian", "locrian 6", "augmented heptatonic", "dorian #4", "lydian diminished", "leading whole tone", "lydian minor", "phrygian dominant", "balinese", "neopolitan major", "harmonic major", "double harmonic major", "hungarian minor", "hungarian major", "oriental", "flamenco", "todi raga", "persian", "enigmatic", "major augmented", "lydian #9", "messiaen's mode #4", "purvi raga", "spanish heptatonic", "bebop minor", "bebop major", "bebop locrian", "minor bebop", "ichikosucho", "minor six diminished", "half-whole diminished", "kafi raga", "messiaen's mode #6", "composite blues", "messiaen's mode #3", "messiaen's mode #7", "chromatic"]
241243
- example: `$('example').randsamp('808').reduce(32).scale(36,51).key('F#', 'bebop').note();`
242244
- example: `$('example').noise(16).scale(30,80).key('c', _.from([1])).note(); // octave scale, via custom FacetPattern`
243245
- example: `$('example').noise(16).scale(30,80).key('c', _.from([1,0,0,0,0,0,0,0,0,0,0,0])).note(); // equivalent to the above custom octave scale; the padded zeroes are optional`
244246
- example: `$('example').noise(16).scale(30,80).key('c', _.from([1,0,0,0,0,0,1])).note(); // octave + perfect fifth scale, via custom FacetPattern`
245-
- example: `$('example').noise(16).scale(30,80).key('c', _.from([1,0,0,0,0,1,0,0,0,0,0,1])).note(); // octave + tritone + major seventh, via custom FacetPattern`
247+
- example: `$('example').noise(16).scale(30,80).key(['c','f#'], ['major','minor']).note(); // the first half is c major; the second half is f# major`
246248
---
247249
- **osc** ( _address_ )
248250
- sends a packet of OSC data to OSC address `address` for every value in the FacetPattern's data.

js/FacetPattern.js

Lines changed: 152 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ const NYQUIST = SAMPLE_RATE / 2;
1515
const curve_calc = require('./lib/curve_calc.js');
1616
const KarplusStrongString = require('./lib/KarplusStrongString.js').KarplusStrongString;
1717
const Complex = require('./lib/Complex.js');
18-
const { Scale } = require('tonal');
19-
const { Midi } = require("tonal");
18+
const { Scale, Midi } = require('tonal');
2019
const PNG = require('pngjs').PNG;
2120
let cross_platform_slash = process.platform == 'win32' ? '\\' : '/';
2221

@@ -796,12 +795,31 @@ class FacetPattern {
796795
}
797796

798797
key (key_letter = "C", key_scale = "major") {
799-
let chroma_key = this.parseKeyAndScale(key_letter,key_scale);
800-
// check the modulo 12 of each variable. if it's 0, move it up 1 and try again. try 12 times then quit
798+
if ( !Array.isArray(key_scale) ) {
799+
key_scale = [key_scale];
800+
}
801+
if (!this.isFacetPattern(key_letter)) {
802+
key_letter = new FacetPattern().from(key_letter);
803+
}
804+
if (!this.isFacetPattern(key_scale)) {
805+
key_scale = new FacetPattern().from(key_scale);
806+
}
807+
let same_size_arrays = this.makePatternsTheSameSize(key_letter, key_scale);
808+
key_letter = same_size_arrays[0].data;
809+
key_scale = same_size_arrays[1].data;
810+
811+
let dataLength = this.data.length;
812+
let keyLetterLength = key_letter.length;
813+
let keyScaleLength = key_scale.length;
814+
801815
let key_sequence = [];
802816
for (let [k, step] of Object.entries(this.data)) {
817+
let keyLetterIndex = Math.floor((k / dataLength) * keyLetterLength);
818+
let keyScaleIndex = Math.floor((k / dataLength) * keyScaleLength);
819+
let chroma_key = this.parseKeyAndScale(key_letter[keyLetterIndex], key_scale[keyScaleIndex]);
820+
803821
if (step < 0) {
804-
key_sequence.push(-1);
822+
key_sequence.push(-1000);
805823
continue;
806824
}
807825
step = Math.round(step);
@@ -820,7 +838,7 @@ class FacetPattern {
820838
i++;
821839
}
822840
if ( key_found == false ) {
823-
key_sequence.push(-1);
841+
key_sequence.push(-1000);
824842
}
825843
}
826844
this.key_scale = key_scale;
@@ -2962,75 +2980,95 @@ rechunk (numChunks, probability = 1) {
29622980
}
29632981

29642982
chord (chord_name, inversion_mode = 0) {
2965-
if ( this.isFacetPattern(chord_name) ) {
2966-
this.chord_intervals = chord_name.data;
2983+
if ( !Array.isArray(chord_name) ) {
2984+
chord_name = [chord_name];
29672985
}
2968-
else {
2969-
const VALID_CHORD_NAMES = [
2970-
'maj', 'major',
2971-
'min', 'minor',
2972-
'fifth', '5th', '5',
2973-
'seventh', '7th', '7',
2974-
'major seventh', 'maj7',
2975-
'minor seventh', 'm7',
2976-
'diminished', 'dim',
2977-
'add2', 'add9'
2978-
];
2979-
if ( !VALID_CHORD_NAMES.includes(chord_name) ) {
2980-
throw `invalid chord name: ${chord_name}`;
2986+
for (var i = 0; i < chord_name.length; i++) {
2987+
let cn = chord_name[i];
2988+
if ( this.isFacetPattern(cn) ) {
2989+
this.chord_intervals.push(cn.data);
29812990
}
2982-
2983-
let chord_intervals_to_add = [];
2984-
switch (chord_name) {
2985-
case 'maj':
2986-
chord_intervals_to_add = [4,7];
2987-
case 'major':
2988-
chord_intervals_to_add = [4,7];
2989-
case 'min':
2990-
chord_intervals_to_add = [3,7];
2991-
case 'minor':
2991+
else {
2992+
const VALID_CHORD_NAMES = [
2993+
'maj', 'major',
2994+
'min', 'minor',
2995+
'fifth', '5th', '5',
2996+
'seventh', '7th', '7',
2997+
'major seventh', 'maj7',
2998+
'minor seventh', 'm7',
2999+
'diminished', 'dim',
3000+
'add2', 'add9'
3001+
];
3002+
if ( !VALID_CHORD_NAMES.includes(cn) ) {
3003+
throw `invalid chord name: ${cn}`;
3004+
}
3005+
3006+
let chord_intervals_to_add = [];
3007+
switch (cn) {
3008+
case 'maj':
3009+
chord_intervals_to_add = [4,7];
3010+
case 'major':
3011+
chord_intervals_to_add = [4,7];
3012+
break;
3013+
case 'min':
29923014
chord_intervals_to_add = [3,7];
2993-
case 'fifth':
2994-
chord_intervals_to_add = [7];
2995-
case '5th':
2996-
chord_intervals_to_add = [7];
2997-
case 'seventh':
2998-
chord_intervals_to_add = [4,7,10];
2999-
case '7th':
3000-
chord_intervals_to_add = [4,7,10];
3001-
case 'major seventh':
3002-
chord_intervals_to_add = [4,7,11];
3003-
case 'maj7':
3004-
chord_intervals_to_add = [4,7,11];
3005-
case 'minor seventh':
3006-
chord_intervals_to_add = [3,7,10];
3007-
case 'm7':
3008-
chord_intervals_to_add = [3,7,10];
3009-
case 'diminished':
3010-
chord_intervals_to_add = [-1,2,5];
3011-
case 'dim':
3012-
chord_intervals_to_add = [-1,2,5];
3013-
case 'add2':
3014-
chord_intervals_to_add = [2,4,7];
3015-
case 'add9':
3016-
chord_intervals_to_add = [4,7,14];
3017-
break;
3018-
default:
3019-
}
3020-
3021-
if ( inversion_mode == 1 ) {
3022-
chord_intervals_to_add[0] -= 12;
3023-
}
3024-
else if ( inversion_mode == 2 ) {
3025-
chord_intervals_to_add[0] -= 12;
3026-
chord_intervals_to_add[1] -= 12;
3027-
}
3028-
else if ( inversion_mode == 3 ) {
3029-
chord_intervals_to_add[0] -= 12;
3030-
chord_intervals_to_add[1] -= 12;
3031-
chord_intervals_to_add[2] -= 12;
3015+
break;
3016+
case 'minor':
3017+
chord_intervals_to_add = [3,7];
3018+
break;
3019+
case 'fifth':
3020+
chord_intervals_to_add = [7];
3021+
break;
3022+
case '5th':
3023+
chord_intervals_to_add = [7];
3024+
break;
3025+
case 'seventh':
3026+
chord_intervals_to_add = [4,7,10];
3027+
break;
3028+
case '7th':
3029+
chord_intervals_to_add = [4,7,10];
3030+
break;
3031+
case 'major seventh':
3032+
chord_intervals_to_add = [4,7,11];
3033+
break;
3034+
case 'maj7':
3035+
chord_intervals_to_add = [4,7,11];
3036+
break;
3037+
case 'minor seventh':
3038+
chord_intervals_to_add = [3,7,10];
3039+
break;
3040+
case 'm7':
3041+
chord_intervals_to_add = [3,7,10];
3042+
break;
3043+
case 'diminished':
3044+
chord_intervals_to_add = [-1,2,5];
3045+
break;
3046+
case 'dim':
3047+
chord_intervals_to_add = [-1,2,5];
3048+
break;
3049+
case 'add2':
3050+
chord_intervals_to_add = [2,4,7];
3051+
break;
3052+
case 'add9':
3053+
chord_intervals_to_add = [4,7,14];
3054+
break;
3055+
default:
3056+
}
3057+
3058+
if ( inversion_mode == 1 ) {
3059+
chord_intervals_to_add[0] -= 12;
3060+
}
3061+
else if ( inversion_mode == 2 ) {
3062+
chord_intervals_to_add[0] -= 12;
3063+
chord_intervals_to_add[1] -= 12;
3064+
}
3065+
else if ( inversion_mode == 3 ) {
3066+
chord_intervals_to_add[0] -= 12;
3067+
chord_intervals_to_add[1] -= 12;
3068+
chord_intervals_to_add[2] -= 12;
3069+
}
3070+
this.chord_intervals.push(chord_intervals_to_add);
30323071
}
3033-
this.chord_intervals = chord_intervals_to_add;
30343072
}
30353073
return this;
30363074
}
@@ -4559,23 +4597,33 @@ ffilter (minFreqs, maxFreqs, invertMode = false) {
45594597
const minIndex = 0;
45604598
const maxIndex = this.data.length - 1;
45614599

4600+
const chordIntervalsLength = this.chord_intervals.length;
4601+
45624602
for (let i = 0; i < sliceSize; i++) {
45634603
const pitches = [];
45644604
for (let j = 0; j < sliceSize; j++) {
45654605
const index = j * sliceSize + i;
45664606
if (this.data[index] !== 0) {
45674607
const midiNoteNumber = Math.round((index - minIndex) / (maxIndex - minIndex) * (maxNote - minNote) + minNote);
4568-
for (var c = 0; c < this.chord_intervals.length; c++) {
4569-
let note_to_add = midiNoteNumber + this.chord_intervals[c];
4608+
let chordIntervalIndex = Math.floor((index / this.data.length) * chordIntervalsLength);
4609+
let currentChordInterval = this.chord_intervals[chordIntervalIndex];
4610+
for (var c = 0; c < currentChordInterval.length; c++) {
4611+
let note_to_add = midiNoteNumber + currentChordInterval[c];
45704612
// check if key needs to be locked
4571-
if ( this.key_scale !== false ) {
4572-
if ( typeof this.key_scale == 'object' ) {
4613+
if (this.key_scale !== false) {
4614+
let dataLength = this.data.length;
4615+
let keyLetterLength = this.key_letter.length;
4616+
let keyScaleLength = this.key_scale.length;
4617+
4618+
let keyLetterIndex = Math.floor((index / dataLength) * keyLetterLength);
4619+
let keyScaleIndex = Math.floor((index / dataLength) * keyScaleLength);
4620+
4621+
if (typeof this.key_scale[keyScaleIndex] == 'object') {
45734622
// scale made from FP
4574-
note_to_add = new FacetPattern().from(note_to_add).key(this.key_letter,new FacetPattern().from(this.key_scale.data)).data[0];
4575-
}
4576-
else {
4577-
// scale from string
4578-
note_to_add = new FacetPattern().from(note_to_add).key(this.key_letter,this.key_scale).data[0];
4623+
note_to_add = new FacetPattern().from(note_to_add).key([this.key_letter[keyLetterIndex]], new FacetPattern().from(this.key_scale[keyScaleIndex].data)).data[0];
4624+
} else {
4625+
// scale from string
4626+
note_to_add = new FacetPattern().from(note_to_add).key([this.key_letter[keyLetterIndex]], [this.key_scale[keyScaleIndex]]).data[0];
45794627
}
45804628
}
45814629
pitches.push(Midi.midiToNoteName(note_to_add));
@@ -4612,22 +4660,36 @@ ffilter (minFreqs, maxFreqs, invertMode = false) {
46124660
const sliceSize = Math.ceil(this.data.length / wraps);
46134661
const track = new MidiWriter.Track();
46144662

4663+
const chordIntervalsLength = this.chord_intervals.length;
4664+
46154665
for (let i = 0; i < sliceSize; i++) {
46164666
const pitches = [];
46174667
for (let j = 0; j < wraps; j++) {
46184668
const index = j * sliceSize + i;
4669+
// ideally this would skip notes < 0 but doing so prevents "rests" so for now they remain
4670+
// if (this.data[index] < 0 ) {
4671+
// continue;
4672+
// }
46194673
if (index < this.data.length) {
4620-
for (var c = 0; c < this.chord_intervals.length; c++) {
4621-
let note_to_add = this.data[index] + this.chord_intervals[c];
4674+
let chordIntervalIndex = Math.floor((index / this.data.length) * chordIntervalsLength);
4675+
let currentChordInterval = this.chord_intervals[chordIntervalIndex];
4676+
for (var c = 0; c < currentChordInterval.length; c++) {
4677+
let note_to_add = this.data[index] + currentChordInterval[c];
46224678
// check if key needs to be locked
4623-
if ( this.key_scale !== false ) {
4624-
if ( typeof this.key_scale == 'object' ) {
4625-
// scale made from FP
4626-
note_to_add = new FacetPattern().from(note_to_add).key(this.key_letter,new FacetPattern().from(this.key_scale.data)).data[0];
4627-
}
4628-
else {
4629-
// scale from string
4630-
note_to_add = new FacetPattern().from(note_to_add).key(this.key_letter,this.key_scale).data[0];
4679+
if (this.key_scale !== false) {
4680+
let dataLength = this.data.length;
4681+
let keyLetterLength = this.key_letter.length;
4682+
let keyScaleLength = this.key_scale.length;
4683+
4684+
let keyLetterIndex = Math.floor((index / dataLength) * keyLetterLength);
4685+
let keyScaleIndex = Math.floor((index / dataLength) * keyScaleLength);
4686+
4687+
if (typeof this.key_scale[keyScaleIndex] == 'object') {
4688+
// scale made from FP
4689+
note_to_add = new FacetPattern().from(note_to_add).key([this.key_letter[keyLetterIndex]], new FacetPattern().from(this.key_scale[keyScaleIndex].data)).data[0];
4690+
} else {
4691+
// scale from string
4692+
note_to_add = new FacetPattern().from(note_to_add).key([this.key_letter[keyLetterIndex]], [this.key_scale[keyScaleIndex]]).data[0];
46314693
}
46324694
}
46334695
pitches.push(Midi.midiToNoteName(note_to_add));

0 commit comments

Comments
 (0)