text rendering service and chord detection

This commit is contained in:
2020-03-21 21:46:33 +01:00
committed by smuddy
parent 5dd95153bb
commit 0cb8875f8d
5 changed files with 55 additions and 9 deletions

View File

@@ -1,7 +1,8 @@
export const KEYS = [
'C', 'C#', 'Db', 'D', 'D#', 'Eb', 'E', 'F', 'F#', 'Gb', 'G', 'G#', 'Ab', 'A', 'A#', 'B', 'H',
'c', 'c#', 'db', 'd', 'd#', 'eb', 'e', 'f', 'f#', 'gb', 'g', 'g#', 'ab', 'a', 'a#', 'b', 'h'
'C#', 'C', 'Db', 'D#', 'D', 'Eb', 'E', 'F#', 'F', 'Gb', 'G#', 'G', 'Ab', 'A#', 'A', 'B', 'H',
'c#', 'c', 'db', 'd#', 'd', 'eb', 'e', 'f#', 'f', 'gb', 'g#', 'g', 'ab', 'a#', 'a', 'b', 'h'
];
export const KEYS_REGEX = new RegExp('(' + KEYS.reduce((a, b) => a + '|' + b) + ')', 'gm');
export const KEYS_MAJOR_FLAT = [
'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H',
];

View File

@@ -12,6 +12,6 @@ export class SongDataService {
public list$ = (): Observable<Song[]> => this.dbService.col$('songs');
public read$ = (songId: string): Observable<Song | undefined> => this.dbService.doc$('songs/' + songId);
public update = async (songId: string, data: any): Promise<void> => await this.dbService.doc(songId).update(data);
public update = async (songId: string, data: any): Promise<void> => await this.dbService.doc('songs/' + songId).update(data);
}

View File

@@ -16,7 +16,7 @@ Text Line 1-2
Text Line 2-2
Refrain
c# cb c7 cmaj7 c/e
c c# db c7 cmaj7 c/e
and the chorus
Bridge
@@ -69,6 +69,17 @@ Cool bridge without any chords
expect(sections[1].lines[2].type).toBe(LineType.chord);
expect(sections[1].lines[2].text).toBe(' a d e f g a h c b');
expect(sections[2].lines[0].type).toBe(LineType.chord);
expect(sections[2].lines[0].text).toBe('c# cb c7 cmaj7 c/e');
expect(sections[2].lines[0].text).toBe('c c# db c7 cmaj7 c/e');
// c c# db c7 cmaj7 c/e
console.log(sections[2].lines[0].chords);
expect(sections[2].lines[0].chords).toEqual([
{chord: 'c', length: 2, position: 0},
{chord: 'c#', length: 3, position: 2},
{chord: 'db', length: 3, position: 5},
{chord: 'c', length: 2, position: 8, add: '7'},
{chord: 'c', length: 5, position: 13, add: 'maj7'},
{chord: 'c', length: 3, position: 22, slashChord: 'e'},
]);
});
});

View File

@@ -11,9 +11,18 @@ export enum LineType {
text,
}
export interface Chord {
chord: string;
length: number;
position: number;
slashChord?: string;
add?: string;
}
export interface Line {
type: LineType;
text: string;
chords?: Chord[]
}
export interface Section {
@@ -27,8 +36,8 @@ export interface Section {
})
export class TextRenderingService {
private regexSection = /(Strophe|Refrain|Bridge)/;
private regexChords = /\b([CDEFGAHBcdefgahb](#|##|b|bb|sus|maj|maj7|min|aug|\d+|\/[CDEFGAHBcdefgahb])?\b)/;
constructor() {
}
@@ -47,9 +56,13 @@ export class TextRenderingService {
}
private getLineOfLineText(text: string): Line {
const matches = !!text.match(this.regexChords);
const type = matches ? LineType.chord : LineType.text;
return {type, text}
const regex = /\b(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h)(\/(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h))?(\d+|maj7)?.?\b/mg;
const match = text.match(regex);
const hasMatches = !!match;
const type = hasMatches ? LineType.chord : LineType.text;
return {type, text, chords: hasMatches ? this.readChords(text) : undefined}
}
private getSectionTypeOfLine(line: string): SectionType {
@@ -64,4 +77,24 @@ export class TextRenderingService {
}
}
private readChords(chordLine: string): Chord[] {
let match;
const chords: Chord[] = [];
const regex = /\b(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h)(\/(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h))?(\d+|maj7)?.?\b/mg;
while ((match = regex.exec(chordLine)) !== null) {
const chord: Chord = {
chord: match[1],
length: match[0].length,
position: regex.lastIndex - match[0].length,
};
if (match[3]) chord.slashChord = match[3];
if (match[4]) chord.add = match[4];
chords.push(chord);
}
return chords;
}
}