Skip to content

Commit

Permalink
Waveform (#9)
Browse files Browse the repository at this point in the history
* Add basic sample waveform visualisation
* Toggle help modal
* Improve responsive design
* Stop editing sound label text on 'Enter' key
  • Loading branch information
grddavies authored Feb 4, 2023
1 parent ee13e03 commit 5e5f3ed
Show file tree
Hide file tree
Showing 28 changed files with 621 additions and 273 deletions.
81 changes: 54 additions & 27 deletions src/components/App/App.css
Original file line number Diff line number Diff line change
@@ -1,43 +1,70 @@
#root {
--max-width: 660px;
margin: 0 auto;
text-align: center;
height: 100vh;
display: flex;
flex-direction: column;
}

width: 66vw;
max-width: var(--max-width);
.content {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}

@media (max-width: 900px) {
width: 75vw;
}
.navbar {
background-color: var(--bg-color-2);
height: 50px;
display: flex;
align-items: center;
padding: 0 20px;

@media (max-width: 768px) {
width: 80vw;
& ul {
display: flex;
list-style: none;
margin-left: auto;
}

@media (max-width: 480px) {
width: 90vw;
}
& li {
text-decoration: none;
margin: 0 10px;

&.icon {
& i {
font-size: 36;
}

@media (max-width: 320px) {
width: 98vw;
& a {
cursor: pointer;
color: var(--text-white);
display: flex;
align-items: center;

transition: color 0.25s;
&:hover {
color: var(--purple);
}
}
}
}
}

.App {
.header-title {
margin: 0;
}

footer {
background-color: var(--bg-color-2);
text-align: left;
height: 50px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

.buttonGrid {
width: 100%;
display: grid;
margin-top: clamp(0.125em, 2vh, 3em);
gap: clamp(0.125em, 2vh, 3em) clamp(0.125em, 2vw, 3em);
@media (max-height: 680px) {
display: none;
}

grid-template-columns: repeat(4, 1fr);
/* 3 column grid on small screens */
@media (max-width: 480px) {
grid-template-columns: repeat(3, 1fr);
@media (max-width: 480px) and (max-height: 740px) {
display: none;
}
}
99 changes: 23 additions & 76 deletions src/components/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,91 +1,38 @@
import 'primeflex/primeflex.css';
import { createEffect, createSignal } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { AudioContextManager } from 'src/audio';
import { BiLogosGithub, BiRegularHelpCircle } from 'solid-icons/bi';
import { createSignal } from 'solid-js';

import { ButtonPad, Modal, ParamPanel, SampleExplorer } from 'src/components';
import { NUM_PADS } from 'src/defaults/constants';
import { useAudioContext } from 'src/hooks';
import { SamplerModel } from 'src/models';
import { HelpModal, Sampler } from 'src/components';
import { appInit } from 'src/utils';
import { Defaults } from 'src/defaults/Defaults';

import './App.css';

export function App() {
const appInitialized = appInit(); // Asyncronously load default samples
const audioContext = useAudioContext();

// load files on context load
createEffect(() => {
// Add our reactive AudioContext
const ctx = audioContext();
if (!ctx) {
return;
}
samplers.forEach(async (model) => {
model.audioContext.value = ctx;
await appInitialized;
model.loadBuffer();
});
});

// Initialise samplers
const samplers = Defaults.samples
.slice(0, NUM_PADS)
.map(({ filename, label }) => new SamplerModel(filename, label));

const paramPanels = samplers.map((model) => () => (
<ParamPanel model={model} />
));

// Index of the selected sampler
const [selectedIdx, setSelectedIndex] = createSignal(0);
// Display help modal
const [showHelp, setShowHelp] = createSignal(true);

return (
<>
<Modal
show={showHelp()}
onClose={() => {
if (!AudioContextManager.initialized.value) {
AudioContextManager.init();
}
setShowHelp(false);
}}
buttonText="Ok"
>
<div class="grid">
<div class="col">
<h1>Help</h1>
<ul class="text-left">
<li>Play sounds by hitting the pads</li>
<li>Edit sounds in the control panel</li>
<li>Load new sounds from the sample explorer</li>
<li>Upload your own sounds</li>
<li>Rename pads via the control panel</li>
</ul>
</div>
</div>
</Modal>
<div class="App">
<h1>SoundBored</h1>
<div class="parameterPanel grid grid-nogutter">
<SampleExplorer selectedSampler={samplers[selectedIdx()]} />
<Dynamic component={paramPanels[selectedIdx()]} />
</div>
<div class="buttonGrid">
{samplers.map((x, i) => (
<ButtonPad
model={x}
onClick={() => {
setSelectedIndex(i);
}}
/>
))}
</div>
</div>
<HelpModal show={showHelp()} setShow={setShowHelp} />
<header class="navbar">
<h1 class="header-title">SoundBored</h1>
<ul>
<li class="icon">
<a href="https://github.com/grddavies/soundbored">
<BiLogosGithub size={36} />
</a>
</li>
<li class="icon">
<a onClick={() => setShowHelp(true)}>
<BiRegularHelpCircle size={36} />
</a>
</li>
</ul>
</header>
<main role="main" class="content">
<Sampler appInitialized={appInitialized} />
</main>
<footer />
</>
);
}
5 changes: 4 additions & 1 deletion src/components/ButtonPad/ButtonPad.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
&:last-of-type {
border-top-right-radius: 0px;
border-top-left-radius: 0px;
padding: 0.25em;
padding: 0.25em 0;
margin-top: 1px;
display: flex;
align-items: center;
justify-content: center;
}
}
}
7 changes: 5 additions & 2 deletions src/components/ButtonPad/ButtonPad.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createPointerListeners } from '@solid-primitives/pointer';
import { BiRegularPlay, BiRegularStop } from 'solid-icons/bi';
import { Component, createEffect } from 'solid-js';

import { AudioPlayerNode } from 'src/audio/AudioPlayerNode';
Expand Down Expand Up @@ -91,9 +92,11 @@ export const ButtonPad: Component<ButtonPadProps> = ({ model, onClick }) => {
<canvas ref={canvas!} />
<button ref={playButton!}>
<div class="label">{label()}</div>
<div>&#9658;</div>
<BiRegularPlay size={24} />
</button>
<button ref={stopButton!}>
<BiRegularStop size={24} />
</button>
<button ref={stopButton!}>&#9632;</button>
</div>
);
};
38 changes: 38 additions & 0 deletions src/components/Modal/HelpModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Component, Setter } from 'solid-js';
import { AudioContextManager } from 'src/audio';

import { Modal } from './Modal';

type HelpModalProps = {
show: boolean;
setShow: Setter<boolean>;
};

/**
* Toggleable help modal dialogue
* @param props
* @returns
*/
export const HelpModal: Component<HelpModalProps> = (props) => (
<Modal
show={props.show}
onClose={() => {
if (!AudioContextManager.initialized.value) {
AudioContextManager.init();
}
props.setShow(false);
}}
buttonText="Ok"
>
<div class="grid">
<div class="col">
<h2 class="pb-2">SoundBored</h2>
<div class="text-left">
<div class="py-2">Trigger samples by hitting the pads</div>
<div class="py-2">Load new sounds from the sample explorer</div>
<div class="py-2">Record and upload your own samples</div>
</div>
</div>
</div>
</Modal>
);
13 changes: 11 additions & 2 deletions src/components/Modal/Modal.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
.modal {
@media (max-width: 480px) {
width: 90vw;
}

z-index: 2;
display: flex;
flex-direction: column;
justify-content: center;
width: 50vw;
max-width: calc(0.75 * var(--max-width));
/* max-width: calc(0.75 * var(--max-width)); */
padding: 1.3rem;
min-height: 250px;
position: absolute;
Expand All @@ -19,6 +22,12 @@
position: absolute;
top: 1em;
right: 1em;

& button {
padding: 0.3em 0.6em;
margin-top: -0.5em;
margin-right: -0.5em;
}
}

& .modal-content {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ export const Modal: ParentComponent<ModalProps> = (props) => {
let overlay: HTMLDivElement;
return (
<>
<section ref={modal!} classList={{ modal: true, hidden: !props.show }}>
<div ref={modal!} classList={{ modal: true, hidden: !props.show }}>
<div class="topbar flex flex-row-reverse">
<button onClick={props.onClose}></button>
</div>
<div class="modal-content p-2">{props.children}</div>
{props.buttonText && (
<button onClick={props.onClose}>{props.buttonText}</button>
)}
</section>
</div>
<div
ref={overlay!}
classList={{ 'modal-overlay': true, hidden: !props.show }}
Expand Down
28 changes: 0 additions & 28 deletions src/components/ParamPanel/ParamPanel.css

This file was deleted.

Loading

0 comments on commit 5e5f3ed

Please sign in to comment.