Adding more effects

This commit is contained in:
2025-10-11 16:47:20 +02:00
parent be7ba5fad8
commit 7f150e8bb4
19 changed files with 2495 additions and 9 deletions

View File

@ -13,6 +13,11 @@
saveDuration,
} from "./lib/utils/settings";
import { generateRandomColor } from "./lib/utils/colors";
import {
getRandomProcessor,
getAllProcessors,
} from "./lib/audio/processors/registry";
import type { AudioProcessor } from "./lib/audio/processors/AudioProcessor";
let currentEngineIndex = 0;
let engine = engines[currentEngineIndex];
@ -26,6 +31,11 @@
let playbackPosition = -1;
let waveformColor = generateRandomColor();
let showModal = true;
let isProcessed = false;
let showProcessorPopup = false;
let popupTimeout: ReturnType<typeof setTimeout> | null = null;
const allProcessors = getAllProcessors();
onMount(() => {
audioService.setVolume(volume);
@ -38,6 +48,7 @@
function generateRandom() {
currentParams = engine.randomParams();
waveformColor = generateRandomColor();
isProcessed = false;
regenerateBuffer();
}
@ -71,6 +82,65 @@
downloadWAV(currentBuffer, "synth-sound.wav");
}
function processSound() {
if (!currentBuffer) return;
const processor = getRandomProcessor();
applyProcessor(processor);
}
function processWithSpecificProcessor(processor: AudioProcessor) {
if (!currentBuffer) return;
hideProcessorPopup();
applyProcessor(processor);
}
function handlePopupMouseEnter() {
if (popupTimeout) {
clearTimeout(popupTimeout);
}
showProcessorPopup = true;
popupTimeout = setTimeout(() => {
showProcessorPopup = false;
}, 2000);
}
function handlePopupMouseLeave() {
if (popupTimeout) {
clearTimeout(popupTimeout);
}
popupTimeout = setTimeout(() => {
showProcessorPopup = false;
}, 200);
}
function hideProcessorPopup() {
if (popupTimeout) {
clearTimeout(popupTimeout);
}
showProcessorPopup = false;
}
async function applyProcessor(processor: AudioProcessor) {
if (!currentBuffer) return;
const leftChannel = currentBuffer.getChannelData(0);
const rightChannel = currentBuffer.getChannelData(1);
const [processedLeft, processedRight] = await processor.process(
leftChannel,
rightChannel,
);
currentBuffer = audioService.createAudioBuffer([
processedLeft,
processedRight,
]);
isProcessed = true;
audioService.play(currentBuffer);
}
function handleVolumeChange(event: Event) {
const target = event.target as HTMLInputElement;
volume = parseFloat(target.value);
@ -114,6 +184,9 @@
case "r":
generateRandom();
break;
case "p":
processSound();
break;
case "s":
download();
break;
@ -201,7 +274,30 @@
/>
<div class="bottom-controls">
<button onclick={generateRandom}>Random (R)</button>
<button onclick={mutate}>Mutate (M)</button>
{#if !isProcessed}
<button onclick={mutate}>Mutate (M)</button>
{/if}
<div
class="process-button-container"
role="group"
onmouseenter={handlePopupMouseEnter}
onmouseleave={handlePopupMouseLeave}
>
<button onclick={processSound}>Process (P)</button>
{#if showProcessorPopup}
<div class="processor-popup">
{#each allProcessors as processor}
<button
class="processor-tile"
data-description={processor.getDescription()}
onclick={() => processWithSpecificProcessor(processor)}
>
{processor.getName()}
</button>
{/each}
</div>
{/if}
</div>
<button onclick={download}>Download (D)</button>
</div>
</div>
@ -290,7 +386,7 @@
.engine-button::after {
content: attr(data-description);
position: absolute;
top: calc(100% + 8px);
top: 100%;
left: 0;
padding: 0.5rem 0.75rem;
background-color: #0a0a0a;
@ -490,4 +586,70 @@
.modal-close:hover {
background-color: #ddd;
}
.process-button-container {
position: relative;
}
.processor-popup {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background-color: #000;
border: 2px solid #fff;
padding: 0.75rem;
z-index: 1000;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
width: 450px;
margin-bottom: 0.5rem;
}
.processor-tile {
background-color: #1a1a1a;
border: 1px solid #444;
padding: 0.6rem 0.4rem;
text-align: center;
cursor: pointer;
transition: background-color 0.2s, border-color 0.2s;
font-size: 0.85rem;
color: #fff;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.processor-tile:hover {
background-color: #2a2a2a;
border-color: #646cff;
}
.processor-tile::after {
content: attr(data-description);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
padding: 0.5rem 0.75rem;
background-color: #0a0a0a;
border: 1px solid #444;
color: #ccc;
font-size: 0.85rem;
width: max-content;
max-width: 300px;
white-space: normal;
word-wrap: break-word;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
z-index: 1001;
margin-bottom: 0.25rem;
}
.processor-tile:hover::after {
opacity: 1;
}
</style>