Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,11 @@ import { Routes, RouterModule } from '@angular/router';

import { ChordsComponent } from './chords/chords.component';
import { ScalesComponent } from './scales/scales.component';
import { ProgressionsComponent } from './progressions/progressions.component';
import { PiecesComponent } from './pieces/pieces.component';

const routes: Routes = [
{ path: '', redirectTo: '/chords', pathMatch: 'full' },
{ path: 'chords', component: ChordsComponent },
{ path: 'scales', component: ScalesComponent },
{ path: 'progressions', component: ProgressionsComponent },
{ path: 'pieces', component: PiecesComponent },
];

@NgModule({
Expand Down
18 changes: 2 additions & 16 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,10 @@ import { PianoComponent } from './piano/piano.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ChordsComponent } from './chords/chords.component';
import { ScalesComponent } from './scales/scales.component';
import { ProgressionsComponent } from './progressions/progressions.component';
import { PiecesComponent } from './pieces/pieces.component';

@NgModule({
declarations: [
AppComponent,
PianoComponent,
ChordsComponent,
ScalesComponent,
ProgressionsComponent,
PiecesComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule,
],
declarations: [AppComponent, PianoComponent, ChordsComponent, ScalesComponent],
imports: [BrowserModule, AppRoutingModule, BrowserAnimationsModule, FormsModule],
providers: [],
bootstrap: [AppComponent],
})
Expand Down
6 changes: 3 additions & 3 deletions src/app/chords/chords.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
<p *ngIf="!chordQuestionGenerator.question">No chords enabled!</p>
<input type="checkbox"
[(ngModel)]="chordQuestionGenerator.enableSharps"
(change)="chordQuestionGenerator.generateChordNames()">
(change)="chordQuestionGenerator.generateQuestions()">
Sharps
<input type="checkbox"
[(ngModel)]="chordQuestionGenerator.enableNaturals"
(change)="chordQuestionGenerator.generateChordNames()">
(change)="chordQuestionGenerator.generateQuestions()">
Naturals
<br />
<br />
<h3>Enabled chord types</h3>
<div *ngFor="let item of chordQuestionGenerator.enableChords | keyvalue">
<input type="checkbox"
[(ngModel)]="chordQuestionGenerator.enableChords[item.key]"
(change)="chordQuestionGenerator.generateChordNames()">
(change)="chordQuestionGenerator.generateQuestions()">
{{ chordNames[item.key] }}
</div>
23 changes: 10 additions & 13 deletions src/app/chords/chords.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,34 @@ import { ChangeDetectorRef } from '@angular/core';
import { PianoService } from '../piano/piano.service';
import { Subscription } from 'rxjs';
import { ChordQuestionGenerator } from './chords';
import { chordNames } from '../data';
import { chordNames } from '../utils/data';

@Component({
selector: 'app-chords',
templateUrl: './chords.component.html',
styleUrls: ['./chords.component.scss'],
})
export class ChordsComponent implements OnInit, OnDestroy {
public chordQuestionGenerator = new ChordQuestionGenerator();
public chordQuestionGenerator: ChordQuestionGenerator;
public chordNames = chordNames;

private chordSubscription: Subscription;
private chordQuestionSubscription: Subscription;

constructor(
private ref: ChangeDetectorRef,
private ref: ChangeDetectorRef, //
private pianoService: PianoService
) {
this.chordSubscription = this.pianoService.chordsSource.subscribe(
chords => {
if (this.chordQuestionGenerator.checkAnswer(chords)) {
this.chordQuestionGenerator.nextQuestion();
}
this.ref.detectChanges();
}
);
this.chordQuestionGenerator = new ChordQuestionGenerator(pianoService);
this.chordQuestionSubscription = this.chordQuestionGenerator.pageUpdateSource.subscribe(() => {
this.ref.detectChanges();
});
}

ngOnInit() {}

ngOnDestroy() {
// prevent memory leak when component destroyed
this.chordSubscription.unsubscribe();
this.chordQuestionGenerator.destroy();
this.chordQuestionSubscription.unsubscribe();
}
}
67 changes: 34 additions & 33 deletions src/app/chords/chords.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,59 @@
import { numToString } from '../data';
import { chordpatterns } from '../data';
import { numToString } from '../utils/data';
import { chordpatterns } from '../utils/data';
import { QuestionGenerator } from '../models/questionGenerator';
import { PianoService } from '../piano/piano.service';
import { Subject, Subscription } from 'rxjs';

export class ChordQuestionGenerator implements QuestionGenerator {
public enabledQuestions = [];
public question = '';
public pageUpdateSource = new Subject<void>();

private chordSubscription: Subscription;

export class ChordQuestionGenerator {
public enableSharps = false;
public enableNaturals = true;
public enableChords = {
'': false,
'': true,
7: false,
maj7: false,
m: false,
m7: false,
mmaj7: false,
dim: false,
dim7: true,
dim7: false,
};

public enabledChordNames = [];
public question = '';
constructor(pianoService: PianoService) {
this.generateQuestions();
this.chordSubscription = pianoService.chordsSource.subscribe(chords => {
if (this.checkAnswer(chords)) {
this.nextQuestion();
}
});
}

public generateChordNames() {
this.enabledChordNames = [];
public generateQuestions() {
this.enabledQuestions = [];
for (let root = 21; root < 33; root++) {
const note = numToString(root, false);
if (
(note.length === 1 || this.enableSharps) &&
(note.length === 2 || this.enableNaturals)
) {
for (const pat of Object.keys(chordpatterns).filter(
patt => this.enableChords[patt]
)) {
this.enabledChordNames.push(note + ' ' + pat);
if ((note.length === 1 || this.enableSharps) && (note.length === 2 || this.enableNaturals)) {
for (const pat of Object.keys(chordpatterns).filter(patt => this.enableChords[patt])) {
this.enabledQuestions.push(note + ' ' + pat);
}
}
}
console.log(this.enabledChordNames);
this.nextQuestion();
}

constructor() {
this.generateChordNames();
}

public nextQuestion() {
this.question =
this.enabledChordNames[
Math.floor(Math.random() * this.enabledChordNames.length)
];
return this.question;
this.question = this.enabledQuestions[Math.floor(Math.random() * this.enabledQuestions.length)];
this.pageUpdateSource.next();
}
public destroy() {
this.chordSubscription.unsubscribe();
}

public checkAnswer(chords: string[]) {
if (chords.includes(this.question)) {
return true;
}
return false;
private checkAnswer(chords: string[]) {
return chords.includes(this.question);
}
}
10 changes: 10 additions & 0 deletions src/app/models/questionGenerator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Subject } from 'rxjs';

export interface QuestionGenerator {
question: string;
enabledQuestions: string[];
pageUpdateSource: Subject<void>;
generateQuestions(): void;
nextQuestion(): void;
destroy(): void;
}
3 changes: 0 additions & 3 deletions src/app/piano/piano.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
<div class="btn-group" role="group" aria-label="Basic example">
<a class="btn" [ngClass]="{'btn-primary': router.url === '/chords', 'btn-outline-primary': router.url !== '/chords'}" routerLink="/chords">Chords</a>
<a class="btn" [ngClass]="{'btn-primary': router.url === '/scales', 'btn-outline-primary': router.url !== '/scales'}" routerLink="/scales">Scales</a>
<a class="btn" [ngClass]="{'btn-primary': router.url === '/intervals', 'btn-outline-primary': router.url !== '/intervals'}">Intervals</a>
<a class="btn" [ngClass]="{'btn-primary': router.url === '/progressions', 'btn-outline-primary': router.url !== '/progressions'}" routerLink="/progressions">Progressions</a>
<a class="btn" [ngClass]="{'btn-primary': router.url === '/pieces', 'btn-outline-primary': router.url !== '/pieces'}" routerLink="/pieces">Pieces</a>
</div>
</div>
</div>
Expand Down
33 changes: 9 additions & 24 deletions src/app/piano/piano.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { octaves, noteNames, generateChords, enharmonicNotes } from '../data';
import { enharmonicNotes, generateChords, noteNames, octaves } from '../utils/data';
import { arraysEqual } from '../utils/utils';

@Injectable({
providedIn: 'root',
Expand All @@ -10,24 +11,24 @@ export class PianoService {
private activeNotes = [];
private chords = generateChords();

notesSource = new Subject<Object>();
notesSource = new Subject<object>();
noteSource = new Subject<string>();
chordsSource = new Subject<string[]>();

constructor() {
for (let i of octaves) {
for (let j of noteNames) {
for (const i of octaves) {
for (const j of noteNames) {
this.notes[j + i] = false;
}
}
}
private detectChord() {
// List of notes current pressed without octave numbers
var notes = this.activeNotes.map(note => note.slice(0, -1)).sort();
var uniqueNotes = Array.from(new Set(notes));
const notes = this.activeNotes.map(note => note.slice(0, -1)).sort();
const uniqueNotes = Array.from(new Set(notes));
// Find chord
let chords: string[] = [];
for (let chordName in this.chords) {
const chords: string[] = [];
for (const chordName in this.chords) {
if (arraysEqual(uniqueNotes, this.chords[chordName])) {
chords.push(chordName);
const splitChord = chordName.split(' ');
Expand All @@ -51,19 +52,3 @@ export class PianoService {
this.chordsSource.next(this.detectChord());
}
}

function arraysEqual(a, b) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;

// If you don't care about the order of the elements inside
// the array, you should sort both arrays here.
// Please note that calling sort on an array will modify that array.
// you might want to clone your array first.

for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
3 changes: 0 additions & 3 deletions src/app/pieces/pieces.component.html

This file was deleted.

Empty file.
23 changes: 0 additions & 23 deletions src/app/pieces/pieces.component.spec.ts

This file was deleted.

36 changes: 0 additions & 36 deletions src/app/pieces/pieces.component.ts

This file was deleted.

Loading