change menu and start saving process

convert file to state wip

finish file to state conversion

load in file to state (needs to be fixed in order to properly load some things in)

formatting

Add microkorg sysex decoding

Correctly parse bit array sections

Add sysex encoding and header creation

remove log

Finish format file v1

Fix a definitions

Move stuff around

add file to store functions

Finish prepare_timbre

begin to Setup menu

Gut a lot of stuff, and implement the menu

Begin overhaul of fileupload process

Finish hooking up the menu

clean up

start saving functions

add unused state, mostly finish saveStore

add self reminder

complete store saving process 1

store to simplified store is complete
This commit is contained in:
[poww10s]
2021-04-01 03:54:43 -04:00
committed by Aoife
parent aa429428d5
commit 8a35046237
37 changed files with 3113 additions and 1764 deletions
-247
View File
@@ -1,247 +0,0 @@
.menu,
.menu-true,
.menu-false {
position: fixed;
background: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 99;
top: 0;
left: 0;
bottom: 0;
right: 0;
min-height: 100vh;
min-width: 100vw;
}
.menu-false {
display: none;
}
.menu-true-animation {
-webkit-animation: scale-in-out-tl 0.3s
cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
animation: scale-in-out-tl 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
}
.menu-false-animation {
-webkit-animation: scale-in-out-tl 0.3s
cubic-bezier(0.55, 0.085, 0.68, 0.53) reverse both;
animation: scale-in-out-tl 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53)
reverse both;
}
/* ----------------------------------------------
* Generated by Animista on 2020-11-21 14:21:54
* Licensed under FreeBSD License.
* See http://animista.net/license for more info.
* w: http://animista.net, t: @cssanimista
* ---------------------------------------------- */
/**
* ----------------------------------------
* animation scale-out-tl
* ----------------------------------------
*/
@-webkit-keyframes scale-in-out-tl {
0% {
-webkit-transform: scale(1);
transform: scale(1);
clip-path: circle(100%);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
opacity: 1;
}
100% {
-webkit-transform: scale(0);
transform: scale(0);
clip-path: circle(0%);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
opacity: 0;
}
}
@keyframes scale-in-out-tl {
0% {
-webkit-transform: scale(1);
transform: scale(1);
-webkit-transform-origin: 0 0;
clip-path: circle(100%);
transform-origin: 0 0;
opacity: 1;
}
100% {
-webkit-transform: scale(0);
transform: scale(0);
clip-path: circle(0%);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
opacity: 0;
}
}
.menu-logo {
height: 40vmin;
pointer-events: none;
padding: 0.5em;
-webkit-user-drag: none;
-khtml-user-drag: none;
-moz-user-drag: none;
-o-user-drag: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
}
.menu-title {
color: #1c1d21;
font-family: 'Lato', sans-serif;
line-height: 1em;
margin: 0 0 0.5em 0;
}
h1 {
margin: 0.25em;
font-weight: 700;
line-height: 0.85em;
font-size: 2.5em;
}
h2 {
margin: 0.25em;
font-weight: 500;
line-height: 1em;
font-size: 1em;
}
.menu-button,
.menu-open-button {
background: transparent;
display: inline-block;
margin: 1em;
padding: 0.35em 1em;
border: 0.1em solid slateblue;
border-radius: 0.12em;
color: slateblue;
font-family: 'Roboto', sans-serif;
font-size: 1em;
font-weight: 300;
text-align: center;
outline: none;
transition: all 0.2s ease-in-out;
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
}
.menu-button:hover {
color: white;
background: slateblue;
}
.menu-open-button:hover {
color: white;
background: #ef476f;
}
.menu-open-button {
z-index: 100;
height: 1.495em;
line-height: 0.9em;
position: absolute;
padding: 0em 0.3em;
color: #ef476f;
border: 0.09em solid #ef476f;
margin: 0;
top: 0.55em;
left: 0.5em;
}
/* change how the button is handled when screen is smaller then 880px*/
.menu-open-button::before {
content: '\2630';
}
.modal {
margin: auto;
height: 8em;
width: 14em;
position: fixed;
z-index: 100;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.modal-hide {
display: none;
}
.modal-display {
display: block;
}
.modal-main {
background: white;
padding: 0.75em 0 1em;
border: solid 0.09em slategrey;
border-radius: 6px;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.modal-header {
font-size: 0.75em;
line-height: 1.25em;
text-align: left;
margin: 0em 9em 0 0;
}
.modal-text {
flex-grow: 3;
margin: 0.5em 0em 1em 1.85em;
text-align: left;
line-height: 1.5em;
font-size: 0.65em;
font-weight: 300;
}
.button-save,
.button-no-save,
.button-cancel {
width: 25%;
font-size: 0.5em;
margin: 0 0.5em;
border-radius: 0.2em;
padding: 0.35em 0;
}
.button-save {
color: mediumseagreen;
border-color: mediumseagreen;
}
.button-save:hover {
background: mediumseagreen;
}
.button-no-save {
color: crimson;
border-color: crimson;
}
.button-no-save:hover {
background: crimson;
}
.button-cancel {
color: slategray;
border-color: grey;
}
.button-cancel:hover {
background: slategray;
}
-146
View File
@@ -1,146 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import IO from '../io/IO';
import { useDispatch, useSelector } from 'react-redux'; // probably temporarily here
import { parameterRefreshAll } from '../timbre/parameters/parameterSlice'; // probably temporarily here
import logo from '../../1f3b9.svg';
import './Menu.css';
// for things such as (do you want to save? or do you want to reset things?)
const Modal = ({ children, show, setShow }) => {
const node = useRef();
const modalDisplay = show ? 'modal modal-display' : 'modal modal-hide';
useEffect(() => {
const current = node.current;
const handleOutsideClick = (event) => {
console.log('clicking anywhere');
if (current.contains(event.target)) {
return;
} else setShow();
};
if (show) {
document.addEventListener('mousedown', handleOutsideClick);
} else {
document.removeEventListener('mousedown', handleOutsideClick);
}
return () => {
document.removeEventListener('mousedown', handleOutsideClick);
};
}, [show, setShow]);
return (
<div ref={node} className={modalDisplay}>
{children}
</div>
);
};
export default function MainMenu() {
const unsaved = useSelector((state) => state.parameters.unsaved);
const [open, setOpen] = useState({
className: '',
openState: true,
});
const [showModal, setShowModal] = useState({
saveCheck: false,
ioModal: false,
});
const dispatch = useDispatch();
const HandleClick = () => {
setOpen({
className: open.openState
? 'menu-true-animation'
: 'menu-false-animation',
openState: !open.openState,
});
};
const AnimationEnd = () => {
setOpen({
...open,
className: `menu-${open.openState}`,
});
};
const showSaveCheck = () => {
setShowModal({ ...showModal, saveCheck: !showModal.saveCheck });
};
const showIOModal = () => {
setShowModal({ ...showModal, ioModal: !showModal.ioModal });
};
return (
<div>
<Modal show={showModal.saveCheck} setShow={showSaveCheck}>
<div className="modal-main">
<span className="modal-header">Save Changes</span>
<span className="modal-text">
Do you want to save your changes?
</span>
<button
className="menu-button button-save"
onClick={() => {
showSaveCheck();
HandleClick();
}} // temporary while I implement the binary parsing stuff
>
Save Changes
</button>
<button
className="menu-button button-no-save"
onClick={() => {
dispatch(parameterRefreshAll());
showSaveCheck();
HandleClick();
}}>
Don't Save
</button>
<button
className="menu-button button-cancel"
onClick={showSaveCheck}>
Cancel
</button>
</div>
</Modal>
<div
className={`menu ${open.className}`}
onAnimationEnd={AnimationEnd}>
<img
src={logo}
className="menu-logo"
alt="logo"
draggable={false}
/>
<header className="menu-title">
<h1>Alapatch</h1>
<h2>A microKORG Patch Editor</h2>
</header>
<div className="menu-button-container">
<button
className="menu-button"
onClick={() => {
!unsaved ? HandleClick() : showSaveCheck();
}}>
New Patch
</button>
<button
className="menu-button"
onClick={() => {
!unsaved ? showIOModal() : showSaveCheck();
}}>
Load Patch
</button>
</div>
</div>
<Modal show={showModal.ioModal} setShow={showIOModal}>
<IO />
</Modal>
<button className="menu-open-button" onClick={HandleClick} />
</div>
);
}
+148
View File
@@ -0,0 +1,148 @@
import { useRef, useState, useEffect } from 'react';
import './menu.css';
import { SelectList } from '../helpers/Helpers';
import { useDispatch, useSelector } from 'react-redux';
import {
parameterUpdateIndex,
parameterUpdated,
parameterFromFile,
parameterRefreshAll,
selectEntities,
} from '../timbre/parameters/parameterSlice'; // probably temporarily here
import { return_store_from_file, return_file_from_store } from '../io';
export default function Menu() {
const [file, setFile] = useState(null);
const fileRef = useRef(null);
const state = useSelector((state) => selectEntities(state));
const dispatch = useDispatch();
const reader = new FileReader();
const loadFile = (f) => {
reader.onloadend = (e) => {
setFile(new Uint8Array(e.target.result));
};
reader.readAsArrayBuffer(f);
};
useEffect(() => {
if (file) {
dispatch(parameterFromFile(return_store_from_file(file)));
}
}, [file, dispatch]);
return (
<div className='menu'>
<div className='menu-patch-container'>
<div className='patch-name'>
<input
placeholder='Patch Name'
type='text'
maxLength='12'
value={state.patch.name}
onChange={(e) => {
dispatch(
parameterUpdated({
id: 'Patch',
changes: { name: e.target.value },
})
);
}}
/>
</div>
<div className='patch-load'>
<button
className='menu-button'
onClick={() => {
dispatch(parameterRefreshAll());
}}>
New Patch
</button>
<button
className='menu-button'
onClick={() => {
fileRef.current.click();
}}>
Load Patch
</button>
<button
className='menu-button'
onClick={() => {
return_file_from_store(state);
}}>
Save Patch
</button>
<input
type='file'
accept='.syx'
className='menu-file-input'
ref={fileRef}
onChange={(e) => {
loadFile(e.target.files[0]);
}}
/>
</div>
<div className='patch-settings'>
<SelectList
value={state.patch.mode}
list={[
{ value: 'Single' },
{ value: 'Multiple' },
{ value: 'Vocoder' },
]}
onChange={(value) => {
dispatch(
parameterUpdated({
id: 'patch',
changes: { mode: value },
})
);
}}
/>
</div>
</div>
<div className='menu-timbre-select'>
<button
disabled={state.patch.mode === 'Vocoder'}
className='menu-button'
onClick={() => {
dispatch(parameterUpdateIndex(0));
}}>
Timbre 1
</button>
<button
disabled={state.patch.mode !== 'Multiple'}
className='menu-button'
onClick={() => {
dispatch(parameterUpdateIndex(1));
}}>
Timbre 2
</button>
<button
disabled={state.patch.mode !== 'Vocoder'}
className='menu-button'
onClick={() => {
dispatch(parameterUpdateIndex(2));
}}>
Vocoder
</button>
<button
className='menu-button'
onClick={() => {
dispatch(parameterUpdateIndex(3));
}}>
Effects
</button>
<button
className='menu-button'
onClick={() => {
dispatch(parameterUpdateIndex(4));
}}>
Arpeggio
</button>
</div>
<div className='menu-title'>
Alapatch <br /> A microKORG Patch Editor
</div>
</div>
);
}
+54
View File
@@ -0,0 +1,54 @@
.menu {
height: 100vh;
min-width: 15vw;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: space-around;
align-items: stretch;
}
.menu-patch-container > * {
margin-top: 10pt;
}
input[type='text'] {
font-family: 'Roboto', sans-serif;
text-indent: 8pt;
width: 70%;
padding: 6pt 0;
outline: none;
border-radius: 4pt;
border: 1px solid gainsboro;
}
input[type='text']:hover {
border-color: silver;
}
input[type='text']:focus {
border: 2px solid dodgerblue;
}
.menu-button {
width: 65%;
display: block;
padding: 4pt;
margin: 8px auto;
outline: none;
}
h2 {
text-align: left;
font-size: x-large;
font-weight: 400;
}
.menu-file-input {
display: none;
}
.patch-settings {
font-size: small;
width: 75%;
margin: 10pt auto;
line-height: 1.5em;
}