@@ -10,13 +10,14 @@ import {
10
10
ChordDefinition ,
11
11
ChordName ,
12
12
ChordIntervals ,
13
+ ChordIntervalRelations ,
13
14
} from '../constants/chords' ;
14
15
import { HarmonicPosition , Interval , Semitones } from '../constants/intervals' ;
15
16
import { NoteSymbol } from '../constants/note' ;
16
17
import { ScaleIntervals } from '../constants/scales' ;
17
18
import { deconstructName , findNameFromIntervals , findNameFromSymbol } from './utils' ;
18
19
import { PlayaError , whilst } from '../utils' ;
19
- import { distance , rotate , choose , random , interval } from '../tools' ;
20
+ import { rotate , choose , random , interval } from '../tools' ;
20
21
import { isDefined , isNull , isUndefined } from '../utils/types-guards' ;
21
22
import assignOctaves from '../utils/octaves' ;
22
23
import { Scale } from './Scale' ;
@@ -212,7 +213,7 @@ export class Chord extends HarmonyBase {
212
213
*/
213
214
static fromNotes ( notes : NoteSymbol [ ] , octaves ?: Octaves ) : Chord {
214
215
const root = notes [ 0 ] ;
215
- const intervalsArray = R . tail ( notes . map ( ( note ) => distance . interval ( root , note ) ) ) ;
216
+ const intervalsArray = R . tail ( notes . map ( ( note ) => interval . between ( root , note ) ) ) ;
216
217
217
218
if ( intervalsArray . includes ( null ) ) {
218
219
throw new PlayaError ( 'Chord' , `Could not recognize a valid chord from these notes: <${ notes } >` ) ;
@@ -354,13 +355,15 @@ export class Chord extends HarmonyBase {
354
355
static findChordSymbol ( chord : ChordIntervals | string ) : ChordSymbol | string | undefined {
355
356
let chordType : ChordSymbol | string | undefined ;
356
357
const chordIntervals = Object . entries ( ChordIntervals ) ;
358
+ let intervals = chord . split ( ' ' ) as Interval [ ] ;
357
359
358
360
for ( const [ name , symbol ] of chordIntervals ) {
359
- // if (chordType) { // this is so we don't get the empty major
360
- // break;
361
- // }
361
+ const splitSymbol = symbol . split ( ' ' ) as Interval [ ] ;
362
362
363
- if ( symbol === chord ) {
363
+ // figure out if all the intervals are present in the symbol
364
+ const allIntervals = R . all ( ( interval ) => R . includes ( interval , splitSymbol ) , intervals ) ;
365
+
366
+ if ( allIntervals ) {
364
367
chordType = ChordSymbol [ name as ChordName ] ;
365
368
break ;
366
369
}
@@ -370,7 +373,6 @@ export class Chord extends HarmonyBase {
370
373
return chordType ;
371
374
}
372
375
373
- let intervals = chord . split ( ' ' ) ;
374
376
const last = R . last ( intervals ) as string ;
375
377
376
378
try {
@@ -390,8 +392,118 @@ export class Chord extends HarmonyBase {
390
392
391
393
chordType = `${ chordType } add${ last . replace ( / \D / g, '' ) } ` ;
392
394
} catch {
393
- console . error ( "[findChordSymbol] Couldn't find a chord symbol for" , chord ) ;
394
- return ;
395
+ intervals = chord . split ( ' ' ) as Interval [ ] ;
396
+
397
+ const state : Record < string , Interval | null > = {
398
+ second : null ,
399
+ third : null ,
400
+ fourth : null ,
401
+ fifth : null ,
402
+ sixth : null ,
403
+ seventh : null ,
404
+ ninth : null ,
405
+ eleventh : null ,
406
+ thirteenth : null ,
407
+ } ;
408
+
409
+ // verify state
410
+ intervals . forEach ( ( interval ) => {
411
+ if ( [ '2m' , '2M' ] . includes ( interval ) ) {
412
+ state . second = interval ;
413
+ } else if ( [ '3m' , '3M' ] . includes ( interval ) ) {
414
+ state . third = interval ;
415
+ } else if ( [ '4P' ] . includes ( interval ) ) {
416
+ state . fourth = interval ;
417
+ } else if ( [ '4A' , '5d' , '5P' , '5A' ] . includes ( interval ) ) {
418
+ state . fifth = interval ;
419
+ } else if ( [ '6m' , '6M' ] . includes ( interval ) ) {
420
+ state . sixth = interval ;
421
+ } else if ( [ '7m' , '7M' ] . includes ( interval ) ) {
422
+ state . seventh = interval ;
423
+ } else if ( [ '9m' , '9M' ] . includes ( interval ) ) {
424
+ state . ninth = interval ;
425
+ } else if ( [ '11P' , '11A' ] . includes ( interval ) ) {
426
+ state . eleventh = interval ;
427
+ } else if ( [ '13m' , '13M' ] . includes ( interval ) ) {
428
+ state . thirteenth = interval ;
429
+ }
430
+ } ) ;
431
+
432
+ const altered : string [ ] = [ ] ;
433
+
434
+ chordType = '' ;
435
+
436
+ // check thirds
437
+ if ( state . third ) {
438
+ chordType = ChordIntervalRelations [ state . third ] ;
439
+ }
440
+
441
+ if ( state . second ) {
442
+ if ( state . second === '2m' ) {
443
+ altered . push ( ChordIntervalRelations [ state . second ] ) ;
444
+ } else {
445
+ chordType = `${ chordType } ${ ChordIntervalRelations [ state . second ] } ` ;
446
+ }
447
+ }
448
+
449
+ if ( state . fourth ) {
450
+ chordType = `${ chordType } ${ ChordIntervalRelations [ state . fourth ] } ` ;
451
+ }
452
+
453
+ if ( state . fifth ) {
454
+ if ( [ '4A' , '5d' ] . includes ( state . fifth ) ) {
455
+ if ( ! state . third ) {
456
+ altered . push ( '#11' ) ;
457
+ } else {
458
+ chordType = `${ chordType } ${ ChordIntervalRelations [ state . fifth ] } ` ;
459
+ }
460
+ }
461
+ }
462
+
463
+ if ( state . sixth ) {
464
+ if ( state . seventh ) {
465
+ state . thirteenth = interval . fromSemitones ( Semitones [ state . sixth ] + 12 ) as any as Interval ;
466
+ } else {
467
+ chordType = `${ chordType } ${ ChordIntervalRelations [ state . sixth ] } ` ;
468
+ }
469
+ }
470
+
471
+ const hasTriad = ! ! state . third || ! ! state . fifth ;
472
+ const hasExtensions = ! ! state . ninth || ! ! state . eleventh || ! ! state . thirteenth ;
473
+ let hasSeventh = false ;
474
+
475
+ if ( state . seventh ) {
476
+ if ( ( hasTriad && ! hasExtensions ) || ( ! hasTriad && hasExtensions ) ) {
477
+ chordType = `${ chordType } ${ ChordIntervalRelations [ state . seventh ] } ` ;
478
+ hasSeventh = true ;
479
+ }
480
+ }
481
+
482
+ if ( state . ninth ) {
483
+ if ( hasSeventh ) {
484
+ altered . push ( ChordIntervalRelations [ state . ninth ] ) ;
485
+ } else {
486
+ chordType = `${ chordType } ${ ChordIntervalRelations [ state . ninth ] } ` ;
487
+ }
488
+ } else if ( state . eleventh ) {
489
+ if ( hasSeventh ) {
490
+ altered . push ( ChordIntervalRelations [ state . eleventh ] ) ;
491
+ } else {
492
+ chordType = `${ chordType } ${ ChordIntervalRelations [ state . eleventh ] } ` ;
493
+ }
494
+ } else if ( state . thirteenth ) {
495
+ if ( hasSeventh ) {
496
+ altered . push ( ChordIntervalRelations [ state . thirteenth ] ) ;
497
+ } else {
498
+ chordType = `${ chordType } ${ ChordIntervalRelations [ state . thirteenth ] } ` ;
499
+ }
500
+ }
501
+
502
+ if ( ! state . third ) {
503
+ altered . push ( 'no3' ) ;
504
+ }
505
+
506
+ return chordType != '' ? `${ chordType } ${ altered . length > 0 ? `(${ altered . join ( ',' ) } )` : '' } ` : undefined ;
395
507
}
396
508
397
509
return chordType ;
0 commit comments