mirror of
https://github.com/chaoticbackup/chaoticbackup.github.io.git
synced 2026-04-18 14:47:29 -05:00
more mugic parser tweaks
This commit is contained in:
parent
5979ea429e
commit
1a88ead718
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
927
package-lock.json
generated
927
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
|
@ -7,7 +7,8 @@
|
|||
"build": "npm run check-types && webpack -p",
|
||||
"check-types": "tsc",
|
||||
"lint": "tsc --noEmit && eslint '*/**/*.{js,ts,tsx}'",
|
||||
"lint:fix": "tsc --noEmit && eslint '*/**/*.{js,ts,tsx}' --quiet --fix"
|
||||
"lint:fix": "tsc --noEmit && eslint '*/**/*.{js,ts,tsx}' --quiet --fix",
|
||||
"test": "cross-env TS_NODE_COMPILER_OPTIONS='{ \"module\": \"commonjs\" }' mocha -r ts-node/register -r ignore-styles -r jsdom-global/register src/**/*.spec.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
@ -56,23 +57,32 @@
|
|||
"@babel/preset-typescript": "^7.9.0",
|
||||
"@babel/register": "^7.9.0",
|
||||
"@babel/runtime": "^7.9.2",
|
||||
"@types/chai": "^4.2.11",
|
||||
"@types/mocha": "^7.0.2",
|
||||
"@types/react": "^16.9.34",
|
||||
"@types/react-dom": "^16.9.7",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.1.0",
|
||||
"chai": "^4.2.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"css-loader": "^3.5.3",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-flowtype": "^4.7.0",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-react": "^7.19.0",
|
||||
"eslint-plugin-react-hooks": "^3.0.0",
|
||||
"ignore-styles": "^5.0.1",
|
||||
"jsdom": "^16.2.2",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"mocha": "^7.1.2",
|
||||
"node-sass": "^4.14.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"sass-loader": "^8.0.2",
|
||||
"style-loader": "^1.2.0",
|
||||
"terser-webpack-plugin": "^2.3.6",
|
||||
"ts-node": "^8.9.1",
|
||||
"typescript": "^3.8.3",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class Attack extends React.Component {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.props.ext == false) return (
|
||||
<div className="card mugic">
|
||||
<img className="thumb" style={{ float: 'left' }} src={API.base_image + (card.gsx$thumb||API.thumb_missing)} onClick={() => this.props.setImage(card.gsx$image)} />
|
||||
|
|
@ -36,7 +36,7 @@ class Attack extends React.Component {
|
|||
<Name name={card.gsx$name} /><br />
|
||||
<Rarity set={card.gsx$set} rarity={card.gsx$rarity} /> <br />
|
||||
<Tribe size="icon16" tribe={card.gsx$tribe} /> Mugic - {card.gsx$tribe}<br />
|
||||
<span>{mugicCounters}</span><MugicPlay notes={card.gsx$notes}/><br />
|
||||
<span>{mugicCounters}</span><MugicPlay notes={card.gsx$shownotes?.length > 0 ? card.gsx$shownotes : card.gsx$notes}/><br />
|
||||
</div>
|
||||
<br />
|
||||
<div className="right" >
|
||||
|
|
|
|||
48
src/components/debounce.js
Normal file
48
src/components/debounce.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// function debounce(f, t) {
|
||||
// return function (args) {
|
||||
// let previousCall = this.lastCall;
|
||||
// this.lastCall = Date.now();
|
||||
// if (previousCall && ((this.lastCall - previousCall) <= t)) {
|
||||
// clearTimeout(this.lastCallTimer);
|
||||
// }
|
||||
// this.lastCallTimer = setTimeout(() => f(args), t);
|
||||
// }
|
||||
// }
|
||||
|
||||
// function debounce2 (func, wait, immediate) {
|
||||
// let timeout;
|
||||
// return function() {
|
||||
// const context = this, args = arguments;
|
||||
// const later = function() {
|
||||
// clearTimeout(timeout);
|
||||
// func.apply(context, args);
|
||||
// };
|
||||
// clearTimeout(timeout);
|
||||
// if (immediate) func.apply(context, args);
|
||||
// else timeout = setTimeout(later, wait);
|
||||
// };
|
||||
// }
|
||||
|
||||
|
||||
/* https://codeburst.io/throttling-and-debouncing-in-javascript-646d076d0a44 */
|
||||
export function debounced(delay, fn) {
|
||||
let timerId;
|
||||
return function (...args) {
|
||||
if (timerId) clearTimeout(timerId);
|
||||
timerId = setTimeout(() => {
|
||||
fn(...args);
|
||||
timerId = null;
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
|
||||
export function throttled(delay, fn) {
|
||||
let lastCall = 0;
|
||||
return function (...args) {
|
||||
const now = (new Date).getTime();
|
||||
if (now - lastCall < delay) return;
|
||||
lastCall = now;
|
||||
return fn(...args);
|
||||
}
|
||||
}
|
||||
|
||||
24
src/components/mugicplayer/mugicparser.spec.ts
Normal file
24
src/components/mugicplayer/mugicparser.spec.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { parseTune, output } from './mugicparser';
|
||||
|
||||
const cases = {
|
||||
"Canon of Casuality": {
|
||||
input: "2Eb 2F 2D 2G 2Bb 1A 3D",
|
||||
output: ["2Eb4", "2F4", "2D4", "2G4", "2Bb5", "1A5", "3D5"]
|
||||
},
|
||||
"Fortissimo": {
|
||||
input: "2G#4 1C#5 2E5 2C#5 2D#5 1G#4 4F#5",
|
||||
output: ["2G#4", "1C#5", "2E5", "2C#5", "2D#5", "1G#4", "4F#5"]
|
||||
}
|
||||
}
|
||||
|
||||
Object.entries(cases).forEach(([key, value]) => {
|
||||
describe(key, () => {
|
||||
it('should return ' + value.output, () => {
|
||||
const tune = output(parseTune(value.input));
|
||||
expect(tune).to.deep.equal(value.output);
|
||||
});
|
||||
});
|
||||
});
|
||||
249
src/components/mugicplayer/mugicparser.ts
Normal file
249
src/components/mugicplayer/mugicparser.ts
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
export class Note {
|
||||
pitch: string;
|
||||
octave: number;
|
||||
time: number;
|
||||
duration: number;
|
||||
velocity: number;
|
||||
|
||||
constructor(duration: number, time: number, value: {pitch: string, octave: number}, velocity?: number) {
|
||||
this.duration = duration;
|
||||
this.time = time;
|
||||
this.pitch = value.pitch;
|
||||
this.octave = value.octave;
|
||||
if (velocity) this.velocity = velocity;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const output = (seq: Note[]) => {
|
||||
return seq.map(n => n.duration + n.pitch + n.octave.toString())
|
||||
}
|
||||
|
||||
// db notation uses duration (quarter notes) and pitch
|
||||
// 2Eb => E flat for 2 quarter notes
|
||||
export const parseTune = (input: string): Note[] => {
|
||||
let seq: Note[] = [];
|
||||
let time = 0;
|
||||
console.log(input.split(" "));
|
||||
input.split(" ").forEach((note) => {
|
||||
const splitter = /(?:[1-8]{1})/;
|
||||
|
||||
const match = note.match(splitter);
|
||||
if (match === null) throw new Error("invalid_input");
|
||||
|
||||
const dur = parseInt(match[0]);
|
||||
const pitch = note.split(splitter)[1];
|
||||
|
||||
const full_note = /[1-8]{1}[A-Za-z#]{1,2}([1-8]{1})/;
|
||||
if (full_note.test(note)) {
|
||||
const sp = note.match(full_note);
|
||||
if (sp === null) throw new Error("invalid_input");
|
||||
seq.push(new Note(dur, time, { pitch, octave: parseInt(sp[1]) }));
|
||||
}
|
||||
else {
|
||||
seq.push(new Note(dur, time, parseNote(pitch, seq)));
|
||||
}
|
||||
|
||||
time += dur;
|
||||
});
|
||||
|
||||
// If a note is repeated at the same octave, look at trend of last two notes
|
||||
// for (let i = 2; i < seq.length; i++) {
|
||||
// const note = seq[i];
|
||||
// const comp = seq[i-2];
|
||||
// if (note.pitch === comp.pitch && note.octave === comp.octave) {
|
||||
// const pitch = letter_to_number(note.pitch);
|
||||
// seq[i].octave = trend(pitch, i, seq);
|
||||
// }
|
||||
// }
|
||||
|
||||
console.log(output(seq));
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
/*
|
||||
We have an array of previous notes; for the first to cases the octave is middle (4).
|
||||
Now for the third and further note, we'll need to look at the previous notes.
|
||||
First check the "closeness" to the last note (if its within 2.5 notes).
|
||||
Go with the appropriate octave (an A above a G4 would be an A5)
|
||||
But if its not within that closeness, look at the trend.
|
||||
*/
|
||||
/**
|
||||
* Tries to find the closer note to match of the previous notes octave
|
||||
* @note The note's
|
||||
*/
|
||||
const parseNote = (pitch: string, seq: Note[]): {pitch: string, octave: number} => {
|
||||
let octave: number = (() => {
|
||||
// If its the first note its "middle octave"
|
||||
if (seq.length === 0) return 4;
|
||||
|
||||
const l = seq.length - 1;
|
||||
const octave = seq[l].octave;
|
||||
|
||||
const current = pitchValue(pitch, octave);
|
||||
const previous = pitchValue(seq[l]);
|
||||
const distance = compare(previous, current);
|
||||
|
||||
// If its less than 3 pitches of the previous note, use the closest pitch
|
||||
if (distance < 3) {
|
||||
if (distance === 0) return octave;
|
||||
|
||||
if (previous > pitchValue(5, octave)) {
|
||||
if (current < pitchValue(3, octave)) {
|
||||
return octave + 1;
|
||||
}
|
||||
else {
|
||||
return octave;
|
||||
}
|
||||
}
|
||||
else if (previous < pitchValue(3, octave)) {
|
||||
if (current > pitchValue(5, octave)) {
|
||||
return octave - 1;
|
||||
}
|
||||
else {
|
||||
return octave;
|
||||
}
|
||||
}
|
||||
return octave;
|
||||
} else if (l === 0) {
|
||||
if (distance === 3) {
|
||||
if (current > previous) {
|
||||
return octave;
|
||||
}
|
||||
else {
|
||||
return octave + 1;
|
||||
}
|
||||
}
|
||||
else if (current > previous) {
|
||||
return octave;
|
||||
}
|
||||
else if (current < previous) {
|
||||
return octave - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If its further away, look at the previous notes for a trend
|
||||
return trend(current, l, seq);
|
||||
})();
|
||||
|
||||
return {pitch: pitch, octave};
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the last note a step down from the note before?
|
||||
* If so consider that to be a higher weight.
|
||||
* If the pattern is going up, go up, if going down go down with repeated notes
|
||||
* Example, a note 4 away but on a downward trend would be prioritized over a 3 away in the other direction.
|
||||
* If there is no change. Pick the octave the previous notes used.
|
||||
*/
|
||||
/**
|
||||
* Searches for a trend in previous notes to calculate the current octave to be used
|
||||
* For each iteration, the length is reduced so that an older set of notes is compared
|
||||
* @param current The note being calculated
|
||||
* @param l The index of the array to be compared
|
||||
*/
|
||||
const trend = (current: number, l: number, seq: Note[]): number => {
|
||||
if (l < 1) return seq[l].octave;
|
||||
|
||||
let prev = pitchValue(seq[l]);
|
||||
let prev2 = pitchValue(seq[l-1]);
|
||||
console.log(prev2, prev, current);
|
||||
|
||||
// downward trend
|
||||
if (prev2 > prev) {
|
||||
if (prev < current) {
|
||||
return seq[l].octave;
|
||||
}
|
||||
return seq[l].octave - 1;
|
||||
}
|
||||
// upward trend
|
||||
else if (prev2 < prev) {
|
||||
if (prev < current) {
|
||||
return seq[l].octave;
|
||||
}
|
||||
return seq[l].octave + 1;
|
||||
}
|
||||
// same notes
|
||||
else {
|
||||
return trend(current, l-1, seq);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes two pitches and returns the distance between them
|
||||
*/
|
||||
const compare = (one: number, two: number): number => {
|
||||
let res = Math.abs(one - two);
|
||||
if (res < 4) {
|
||||
return res;
|
||||
}
|
||||
else if (res > 3.5) {
|
||||
return res - 1;
|
||||
}
|
||||
else if (res > 4.5) {
|
||||
return res - 2;
|
||||
}
|
||||
else if (res > 5.5) {
|
||||
return res - 3;
|
||||
}
|
||||
else if (res > 6.5) {
|
||||
return res - 4;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function pitchValue(note: Note): number;
|
||||
function pitchValue(letter: number, octave: number): number;
|
||||
function pitchValue(pitch: string, octave: number): number;
|
||||
function pitchValue(arg1: number | string | Note, arg2?: number): number {
|
||||
let pitch: number;
|
||||
let octave: number;
|
||||
if (arg1 instanceof Note) {
|
||||
pitch = letter_to_number(arg1.pitch);
|
||||
octave = arg1.octave;
|
||||
} else {
|
||||
pitch = (typeof arg1 === 'number') ? arg1 : letter_to_number(arg1);
|
||||
octave = arg2 as number;
|
||||
}
|
||||
return pitch + (octave - 1) * 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a pitch to numerical value for calculations
|
||||
*/
|
||||
const letter_to_number = (pitch: string): number => {
|
||||
let num: number;
|
||||
switch (pitch.charAt(0).toUpperCase()) {
|
||||
case "A":
|
||||
num = 1;
|
||||
break;
|
||||
case "B":
|
||||
num = 2;
|
||||
break;
|
||||
case "C":
|
||||
num = 3;
|
||||
break;
|
||||
case "D":
|
||||
num = 4;
|
||||
break;
|
||||
case "E":
|
||||
num = 5;
|
||||
break;
|
||||
case "F":
|
||||
num = 6;
|
||||
break;
|
||||
case "G":
|
||||
num = 7;
|
||||
break;
|
||||
// In the case of incorrect input, coerce note to a C
|
||||
default:
|
||||
num = 3;
|
||||
}
|
||||
if (pitch.length > 1) {
|
||||
if (pitch.charAt(1).toLowerCase() === "b") num -= .5;
|
||||
else if (pitch.charAt(1) === "#") num += .5;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
import {Transport, Synth, Part, Time, PolySynth, EnvelopeCurve} from 'tone';
|
||||
import {Time, Transport, Synth, Part, PolySynth, EnvelopeCurve} from 'tone';
|
||||
|
||||
import { Note, parseTune } from './mugicparser';
|
||||
|
||||
type BasicEnvelopeCurve = "linear" | "exponential";
|
||||
|
||||
// https://github.com/Tonejs/Tone.js/wiki/Time
|
||||
|
|
@ -9,19 +12,11 @@ interface note_value {
|
|||
duration: number,
|
||||
velocity?: number
|
||||
}
|
||||
export class Note {
|
||||
pitch: string;
|
||||
octave: number;
|
||||
time: number;
|
||||
duration: number;
|
||||
velocity: number;
|
||||
|
||||
constructor(duration: number, time: number, value: {pitch: string, octave: number}, velocity?: number) {
|
||||
this.duration = duration;
|
||||
this.time = time;
|
||||
this.pitch = value.pitch;
|
||||
this.octave = value.octave;
|
||||
if (velocity) this.velocity = velocity;
|
||||
class Note_Value extends Note {
|
||||
constructor(note: Note) {
|
||||
const { duration, time, pitch, octave, velocity } = note;
|
||||
super(duration, time, { pitch, octave }, velocity);
|
||||
}
|
||||
|
||||
get value(): note_value {
|
||||
|
|
@ -36,7 +31,7 @@ export class Note {
|
|||
|
||||
export class MugicPlayer {
|
||||
private static instance: MugicPlayer;
|
||||
private synth: PolySynth;
|
||||
private synth: Synth;
|
||||
private part: Part;
|
||||
|
||||
// Singleton
|
||||
|
|
@ -60,10 +55,9 @@ export class MugicPlayer {
|
|||
releaseCurve: "exponential" as EnvelopeCurve,
|
||||
decayCurve: "exponential" as BasicEnvelopeCurve
|
||||
},
|
||||
pitchDecay: 0.05,
|
||||
maxPolyphony: 1
|
||||
pitchDecay: 0.05
|
||||
};
|
||||
this.synth = new PolySynth(Synth, options).toDestination();
|
||||
this.synth = new Synth(options).toDestination();
|
||||
Transport.bpm.value = 140;
|
||||
}
|
||||
|
||||
|
|
@ -79,10 +73,9 @@ export class MugicPlayer {
|
|||
if (this.part) this.part.dispose();
|
||||
|
||||
try {
|
||||
const tune = parseTune(input);
|
||||
console.log(tune.map(n => n.value.pitch));
|
||||
const tune = parseTune(input).map(note => new Note_Value(note));
|
||||
this.part = new Part(
|
||||
(time, val: note_value) => {
|
||||
(time, val) => {
|
||||
this.synth.triggerAttackRelease(val.pitch, val.duration, time, val.velocity);
|
||||
},
|
||||
tune.map((n) => n.value)
|
||||
|
|
@ -99,212 +92,3 @@ export class MugicPlayer {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// db notation uses duration (quarter notes) and pitch
|
||||
// 2Eb => E flat for 2 quarter notes
|
||||
const parseTune = (input: string): Note[] => {
|
||||
let seq: Note[] = [];
|
||||
let time = 0;
|
||||
|
||||
input.split(" ").forEach((note) => {
|
||||
|
||||
let match = note.match(/(?:[1-8]{1})/);
|
||||
if (match === null) throw new Error("invalid_input");
|
||||
|
||||
let dur = parseInt(match[0]);
|
||||
let pitch = note.split(/(?:[1-8]{1})/)[1];
|
||||
|
||||
seq.push(new Note(dur, time, parseNote(pitch, seq)));
|
||||
|
||||
time += dur;
|
||||
});
|
||||
|
||||
// If a note is repeated at the same octave, look at trend of last two notes
|
||||
// for (let i = 2; i < seq.length; i++) {
|
||||
// const note = seq[i];
|
||||
// const comp = seq[i-2];
|
||||
// if (note.pitch === comp.pitch && note.octave === comp.octave) {
|
||||
// const pitch = letter_to_number(note.pitch);
|
||||
// seq[i].octave = trend(pitch, i, seq);
|
||||
// }
|
||||
// }
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
/*
|
||||
We have an array of previous notes; for the first to cases the octave is middle (4).
|
||||
Now for the third and further note, we'll need to look at the previous notes.
|
||||
First check the "closeness" to the last note (if its within 2.5 notes).
|
||||
Go with the appropriate octave (an A above a G4 would be an A5)
|
||||
But if its not within that closeness, look at the trend.
|
||||
*/
|
||||
/**
|
||||
* Tries to find the closer note to match of the previous notes octave
|
||||
* @note The note's
|
||||
*/
|
||||
const parseNote = (pitch: string, seq: Note[]): {pitch: string, octave: number} => {
|
||||
let octave: number = (() => {
|
||||
// If its the first note its "middle octave"
|
||||
if (seq.length === 0) return 4;
|
||||
|
||||
const l = seq.length - 1;
|
||||
const current = pitchValue(pitch, seq[l].octave);
|
||||
const previous = pitchValue(seq[l]);
|
||||
const distance = compare(previous, current);
|
||||
|
||||
// If its less than 3 pitches of the previous note, use the closest pitch
|
||||
if (distance < 3) {
|
||||
if (distance === 0) return seq[l].octave;
|
||||
|
||||
if (previous > 5) {
|
||||
if (current < 3) {
|
||||
return seq[l].octave + 1;
|
||||
}
|
||||
else {
|
||||
return seq[l].octave;
|
||||
}
|
||||
}
|
||||
else if (previous < 3) {
|
||||
if (current > 5) {
|
||||
return seq[l].octave - 1;
|
||||
}
|
||||
else {
|
||||
return seq[l].octave;
|
||||
}
|
||||
}
|
||||
return seq[l].octave;
|
||||
} else if (l === 0) {
|
||||
if (distance === 3) {
|
||||
return seq[l].octave + 1;
|
||||
}
|
||||
else if (current > previous) {
|
||||
return seq[l].octave;
|
||||
}
|
||||
else if (current < previous) return seq[l].octave - 1;
|
||||
}
|
||||
|
||||
// If its further away, look at the previous notes for a trend
|
||||
return trend(current, l, seq);
|
||||
})();
|
||||
|
||||
return {pitch: pitch, octave};
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the last note a step down from the note before?
|
||||
* If so consider that to be a higher weight.
|
||||
* If the pattern is going up, go up, if going down go down with repeated notes
|
||||
* Example, a note 4 away but on a downward trend would be prioritized over a 3 away in the other direction.
|
||||
* If there is no change. Pick the octave the previous notes used.
|
||||
*/
|
||||
/**
|
||||
* Searches for a trend in previous notes to calculate the current octave to be used
|
||||
* For each iteration, the length is reduced so that an older set of notes is compared
|
||||
* @param current The note being calculated
|
||||
* @param l The index of the array to be compared
|
||||
*/
|
||||
const trend = (current: number, l: number, seq: Note[]): number => {
|
||||
if (l < 1) return seq[l].octave;
|
||||
|
||||
let prev = pitchValue(seq[l].pitch, seq[l].octave);
|
||||
let prev2 = pitchValue(seq[l-1].pitch, seq[l-1].octave);
|
||||
|
||||
// downward trend
|
||||
if (prev2 > prev) {
|
||||
if (prev < current) {
|
||||
return seq[l].octave;
|
||||
}
|
||||
return seq[l].octave - 1;
|
||||
}
|
||||
// upward trend
|
||||
else if (prev2 < prev) {
|
||||
if (prev < current) {
|
||||
return seq[l].octave;
|
||||
}
|
||||
return seq[l].octave + 1;
|
||||
}
|
||||
// same notes
|
||||
else {
|
||||
return trend(current, l, seq);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes two pitches and returns the distance between them
|
||||
*/
|
||||
const compare = (one: number, two: number): number => {
|
||||
let res = Math.abs(one - two);
|
||||
if (res < 4) {
|
||||
return res;
|
||||
}
|
||||
else if (res > 3.5) {
|
||||
return res - 1;
|
||||
}
|
||||
else if (res > 4.5) {
|
||||
return res - 2;
|
||||
}
|
||||
else if (res > 5.5) {
|
||||
return res - 3;
|
||||
}
|
||||
else if (res > 6.5) {
|
||||
return res - 4;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function pitchValue(note: Note): number;
|
||||
function pitchValue(current: number, octave: number): number;
|
||||
function pitchValue(pitch: string, octave: number): number;
|
||||
function pitchValue(arg1: number | string | Note, octave?: number): number {
|
||||
let pitch: number;
|
||||
if (arg1 instanceof Note) {
|
||||
pitch = letter_to_number(arg1.pitch);
|
||||
octave = arg1.octave;
|
||||
} else {
|
||||
pitch = (typeof arg1 === 'number') ? arg1 : letter_to_number(arg1);
|
||||
octave = octave as number;
|
||||
}
|
||||
return pitch + (octave - 1) * 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a pitch to numerical value for calculations
|
||||
*/
|
||||
const letter_to_number = (pitch: string): number => {
|
||||
let num: number;
|
||||
switch (pitch.charAt(0).toUpperCase()) {
|
||||
case "A":
|
||||
num = 1;
|
||||
break;
|
||||
case "B":
|
||||
num = 2;
|
||||
break;
|
||||
case "C":
|
||||
num = 3;
|
||||
break;
|
||||
case "D":
|
||||
num = 4;
|
||||
break;
|
||||
case "E":
|
||||
num = 5;
|
||||
break;
|
||||
case "F":
|
||||
num = 6;
|
||||
break;
|
||||
case "G":
|
||||
num = 7;
|
||||
break;
|
||||
// In the case of incorrect input, coerce note to a C
|
||||
default:
|
||||
num = 3;
|
||||
}
|
||||
if (pitch.length > 1) {
|
||||
if (pitch.charAt(1).toLowerCase() === "b") num -= .5;
|
||||
else if (pitch.charAt(1) === "#") num += .5;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
export default MugicPlayer.getInstance();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import React from 'react';
|
||||
import MugicPlayer from './mugicplayer';
|
||||
import {debounced} from '../debounce';
|
||||
import {MugicPlayer} from './mugicplayer';
|
||||
const player = MugicPlayer.getInstance();
|
||||
|
||||
export default (props: any) => (
|
||||
<React.Fragment >
|
||||
<input type="button" value="Play" onClick={() => {MugicPlayer.play(props.notes)}} />
|
||||
</React.Fragment>
|
||||
);
|
||||
export default (props: any) => {
|
||||
const play = debounced(200, () => { player.play(props.notes); });
|
||||
return (
|
||||
<input type="button" value="Play" onClick={() => { play() }} />
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,10 +41,11 @@
|
|||
]
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
"./src"
|
||||
],
|
||||
"exclude": [
|
||||
"./build/*",
|
||||
"./node_modules/*"
|
||||
"./build",
|
||||
"./node_modules/*",
|
||||
"./source/**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user