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 = [ 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 = [ export const KEYS_MAJOR_FLAT = [
'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H', '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 list$ = (): Observable<Song[]> => this.dbService.col$('songs');
public read$ = (songId: string): Observable<Song | undefined> => this.dbService.doc$('songs/' + songId); 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 Text Line 2-2
Refrain Refrain
c# cb c7 cmaj7 c/e c c# db c7 cmaj7 c/e
and the chorus and the chorus
Bridge Bridge
@@ -69,6 +69,17 @@ Cool bridge without any chords
expect(sections[1].lines[2].type).toBe(LineType.chord); 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[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].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, text,
} }
export interface Chord {
chord: string;
length: number;
position: number;
slashChord?: string;
add?: string;
}
export interface Line { export interface Line {
type: LineType; type: LineType;
text: string; text: string;
chords?: Chord[]
} }
export interface Section { export interface Section {
@@ -27,8 +36,8 @@ export interface Section {
}) })
export class TextRenderingService { export class TextRenderingService {
private regexSection = /(Strophe|Refrain|Bridge)/; private regexSection = /(Strophe|Refrain|Bridge)/;
private regexChords = /\b([CDEFGAHBcdefgahb](#|##|b|bb|sus|maj|maj7|min|aug|\d+|\/[CDEFGAHBcdefgahb])?\b)/;
constructor() { constructor() {
} }
@@ -47,9 +56,13 @@ export class TextRenderingService {
} }
private getLineOfLineText(text: string): Line { private getLineOfLineText(text: string): Line {
const matches = !!text.match(this.regexChords); 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 type = matches ? LineType.chord : LineType.text;
return {type, text} 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 { 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;
}
} }

View File

@@ -7,6 +7,7 @@
background: #fffe; background: #fffe;
overflow: hidden; overflow: hidden;
width: 800px; width: 800px;
transition: 3s all ease-in-out;
@media screen and (max-width: 860px) { @media screen and (max-width: 860px) {
width: 100vw; width: 100vw;
border-radius: 0px; border-radius: 0px;