wip simple cases work

This commit is contained in:
Daniel 2019-12-06 16:54:54 -05:00
parent c8f72e0f0e
commit 85af86ec1c
10 changed files with 2692 additions and 929 deletions

View File

@ -1,4 +1,4 @@
module.exports = exports = {
export default exports = {
"root": true,
"parser": "babel-eslint",
"extends": [
@ -8,8 +8,7 @@ module.exports = exports = {
"env": {
"browser": true,
"es6": true,
"node": true,
"amd": true
"node": true
},
"parserOptions": {
"ecmaVersion": 8,

View File

@ -51,7 +51,7 @@
(function(l) {
if (l.search) {
let title = l.search.split('&')[0].split('/')[1];
if (title != "") {
if (title && title != "") {
document.title = title.charAt(0).toUpperCase() + title.slice(1);
}
else {

3282
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,17 +14,21 @@
"author": "Danude Sandstorm",
"license": "MIT",
"dependencies": {
"@loadable/component": "^5.10.3",
"@types/react": "^16.9.9",
"@types/react-dom": "^16.9.2",
"lokijs": "^1.5.7",
"mobx": "^5.13.1",
"@loadable/component": "^5.11.0",
"@material-ui/core": "^4.5.1",
"@material-ui/icons": "^4.5.1",
"@material-ui/styles": "^4.5.0",
"@types/react": "^16.9.15",
"@types/react-dom": "^16.9.4",
"@types/react-router-dom": "^5.1.2",
"lokijs": "^1.5.8",
"mobx": "^5.15.0",
"mobx-react": "^5.4.4",
"prop-types": "^15.7.2",
"react": "^16.10.1",
"react-collapsible": "^2.6.0",
"react": "^16.12.0",
"react-collapsible": "^2.6.2",
"react-digit-input": "^1.0.0",
"react-dom": "^16.10.1",
"react-dom": "^16.12.0",
"react-interactive": "^0.9.1",
"react-loadable": "^5.5.0",
"react-onclickoutside": "^6.9.0",
@ -36,37 +40,51 @@
"whatwg-fetch": "^3.0.0"
},
"devDependencies": {
"@babel/cli": "^7.6.2",
"@babel/core": "^7.6.2",
"@babel/node": "^7.6.2",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-decorators": "^7.6.0",
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-transform-runtime": "^7.6.2",
"@babel/polyfill": "^7.6.0",
"@babel/preset-env": "^7.6.2",
"@babel/preset-flow": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.6.0",
"@babel/register": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/node": "^7.7.4",
"@babel/plugin-proposal-class-properties": "^7.7.4",
"@babel/plugin-proposal-decorators": "^7.7.4",
"@babel/plugin-proposal-dynamic-import": "^7.7.0",
"@babel/plugin-proposal-object-rest-spread": "^7.7.4",
"@babel/plugin-transform-computed-properties": "^7.7.4",
"@babel/plugin-transform-runtime": "^7.7.5",
"@babel/polyfill": "^7.7.0",
"@babel/preset-env": "^7.7.5",
"@babel/preset-flow": "^7.7.4",
"@babel/preset-react": "^7.7.4",
"@babel/preset-typescript": "^7.7.4",
"@babel/register": "^7.7.4",
"@babel/runtime": "^7.7.1",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.5",
"css-loader": "^3.2.0",
"eslint": "^6.5.1",
"css-loader": "^3.2.1",
"eslint": "^6.7.2",
"eslint-plugin-flowtype": "^4.3.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-react": "^7.15.0",
"eslint-plugin-react-hooks": "^2.1.1",
"eslint-plugin-react": "^7.17.0",
"eslint-plugin-react-hooks": "^2.3.0",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.12.0",
"node-sass": "^4.13.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"typescript": "^3.6.4",
"style-loader": "^1.0.1",
"typescript": "^3.7.3",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"webpack-dev-server": "^3.8.1"
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@ -2,6 +2,7 @@ import React from 'react';
import API from '../../SpreadsheetData';
import {observer, inject} from 'mobx-react';
import {Rarity, Unique, Name, Mugic, Ability, Tribe} from '../../Snippets';
import MugicPlay from '../../mugicplayer/playbutton.tsx';
@inject((stores, props, context) => props) @observer
export default class Attack extends React.Component {
@ -34,7 +35,7 @@ export default 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><br />
<span>{mugicCounters}</span><MugicPlay notes={card.gsx$notes}/><br />
</div>
<br />
<div className="right" >

View File

@ -1,43 +1,20 @@
import Tone from 'tone';
const Tone = require('tone');
// https://github.com/Tonejs/Tone.js/wiki/Time
class Note {
// https://github.com/Tonejs/Tone.js/wiki/Events
export class Note {
time: number;
value: {
pitch: string;
octave: number;
}
pitch: string;
octave: number;
constructor(time: number, value: any) {
constructor(time: number, value: {pitch: string, octave: number}) {
this.time = time;
this.value = value;
this.pitch = value.pitch;
this.octave = value.octave;
}
get pair() {
return [this.time * Tone.time("4"), this.value.pitch + this.value.octave.toString()];
}
toNumber (): number {
return
}
}
const letter_to_number = (letter: string): number => {
switch (letter.charAt(0).toUpperCase()) {
case "A":
return 1;
case "B":
return 2;
case "C":
return 3;
case "D":
return 4;
case "E":
return 5;
case "F":
return 6;
case "G":
return 7;
return [this.time + "/4n", this.pitch + this.octave.toString()];
}
}
@ -53,48 +30,176 @@ class MugicPlayer {
constructor() {
this.synth = new Tone.Synth().toMaster();
Tone.Transport.bpm.value = 120;
Tone.Transport.bpm.value = 100;
}
// Example: Canon of Casuality
// 2Eb 2F 2D 2G 2Bb 1A 3D
// up down up up down up
/**
* Composes and plays a tune parsed from the Mugic entry
* @input the string of Mugic notes
*/
play(input: string) {
let pattern: Note[] = [];
input.split(" ").forEach((digit) => {
let tune: Note[] = [];
input.split(" ").forEach((note) => {
// db notation uses duration (quarter notes) and pitch
let [d, n] = digit.split(/[1-8]{1}/);
pattern.push(new Note(parseInt(d), parseNote(n, pattern)));
let d = note.match(/(?:[1-8]{1})/)[0];
let n = note.split(/(?:[1-8]{1})/)[1];
tune.push(new Note(parseInt(d), parseNote(n, tune)));
});
new Tone.Part(
(time: any, pitch: any) => {
this.synth.triggerAttackRelease(pitch, "4n", time);
},
pattern.map((note) => {return note.pair})
).start(0);
Tone.Transport.start();
let output = tune.map((note) => {return note.pair});
console.log(output);
// new Tone.Part(
// (time: any, pitch: any) => {
// this.synth.triggerAttackRelease(pitch, "4n", time);
// },
// tune.map((note) => {return note.pair})
// ).start(0);
// Tone.Transport.start();
}
}
// Example: Canon of Casuality
// Eb 2F 2D 2G 2Bb 1A 3D
// up down up up down up
/**
* Tries to find the closer note to match of the previous notes octave
*/
/*
We have an array of previous notes; for the first to cases the octave is middle (4) easy.
Now for the third and further note, we'll need to look at the previous notes.
First check the "closness" to the last note. (if its within 2.5 notes lets say).
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.
Is the last note a step down from the note before?
If so consider that to be a higher weight. If 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 octive the previous notes used.
*/
export const parseNote = (note: string, seq: Note[]): {pitch: string, octave: number} => {
let octave: number = (() => {
// If its the first two notes
if (seq.length < 2) return 4;
// If going up, go up, if going down go down with repeated notes
// If the first note and last are the same, they share the same octive
// If there is no trend (same note without previous two)
// Try to find the closer note to match with
const parseNote = (note: string, prev: Note[]): {pitch: string, octave: number} => {
let octave: number;
if (prev.length < 2) octave = 4;
else {
//TODO
}
const l = seq.length;
let previous = letter_to_number(seq[l-1].pitch);
let current = letter_to_number(note);
let distance = compare(previous, current);
// If its within two pitches of the previous, use the closest note
if (distance < 3) {
if (distance === 0) return seq[l-1].octave;
if (previous > 5) {
if (current < 3) {
return seq[l-1].octave + 1;
}
else {
return seq[l-1].octave;
}
}
else if (previous < 3) {
if (current > 5) {
return seq[l-1].octave - 1;
}
else {
return seq[l-1].octave;
}
}
return seq[l-1].octave;
}
// If its slightly further away, look at the last two notes for a trend
let prev2 = letter_to_number(seq[l-2].pitch);
// Downward trend
if (prev2 > previous) {
if (previous < current) {
return seq[l-1].octave;
}
return seq[l-1].octave - 1;
}
// upward trend
else if (prev2 < previous) {
if (previous < current) {
return seq[l-1].octave;
}
return seq[l-1].octave + 1;
}
// same notes
else {
}
return 1; // debug shouldn't reach 1
})();
return {pitch: note, octave};
}
/**
* 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;
}
/**
* 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();

View File

@ -0,0 +1,8 @@
import React from 'react';
import MugicPlayer from './mugicplayer';
export default (props: any) => (
<React.Fragment >
<input type="button" value="Play" onClick={() => {MugicPlayer.play(props.notes)}} />
</React.Fragment>
);

View File

@ -30,7 +30,7 @@
"resolveJsonModule": true,
// Library files to be used in the project.
// Tells the compiler that "DOM-APIs" and new ECMAScript features are valid.
"lib": ["dom", "es2018"],
"lib": ["dom", "ES2019"],
// Allows @decorators
"experimentalDecorators": true,
// Skips checking libraries

View File

@ -9,16 +9,16 @@ require('@babel/register');
const devMode = (process.env.NODE_ENV !== 'production' && process.argv.indexOf('-p') === -1);
const config = {
entry: ['@babel/polyfill', `./src/components/index.js`],
entry: ['@babel/polyfill', './src/components/index.js'],
resolve: {
extensions: ['.js', '.jsx'],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
devServer: {
host: '0.0.0.0',
historyApiFallback: {
index: 'index.dev.html',
index: 'index.html',
},
},
@ -78,16 +78,16 @@ const config = {
options: {
presets: [
'@babel/typescript',
'@babel/preset-env',
"@babel/preset-env",
'@babel/preset-react',
'@babel/preset-flow',
],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-object-rest-spread',
['@babel/plugin-proposal-decorators', {legacy: true}],
['@babel/plugin-proposal-class-properties', {loose: true}],
'@babel/plugin-syntax-dynamic-import',
'@babel/proposal-object-rest-spread',
['@babel/plugin-transform-computed-properties', {loose: true}],
],
},
},