diff --git a/src/Board.jsx b/src/Board.jsx index 10bdd41..9c046b0 100644 --- a/src/Board.jsx +++ b/src/Board.jsx @@ -47,6 +47,8 @@ function Board() { isSequencePlaying, startTime, BPM, + totalSteps, + totalBeats, }; const playHeadProps = { diff --git a/src/components/Toolbar.css b/src/components/Toolbar.css index 1188d17..abc344f 100644 --- a/src/components/Toolbar.css +++ b/src/components/Toolbar.css @@ -23,6 +23,18 @@ cursor: pointer; } + .button_save { + margin-left: var(--spacer); + padding: 0 10px; + cursor: pointer; + letter-spacing: 0.05em; + } + + .button_save:disabled { + cursor: progress; + opacity: 0.6; + } + .button_icon_path { fill: var(--color-fg); } diff --git a/src/components/Toolbar.jsx b/src/components/Toolbar.jsx index 5cf7229..25ff0f8 100644 --- a/src/components/Toolbar.jsx +++ b/src/components/Toolbar.jsx @@ -1,6 +1,7 @@ -import { useContext, memo } from "react"; +import { useContext, memo, useState } from "react"; import { sequenceList } from "../constants/config"; import { Context } from "../Provider"; +import { renderSequenceToWav, downloadBlob } from "../utils/exportWav"; import "./Toolbar.css"; const ToolBar = ({ @@ -10,11 +11,12 @@ const ToolBar = ({ isSequencePlaying, startTime, BPM, + totalSteps, + totalBeats, }) => { - const { - sequence: { id: selectedSequenceID }, - selectSequence, - } = useContext(Context); + const { sequence, selectSequence } = useContext(Context); + const { id: selectedSequenceID, title: sequenceTitle } = sequence; + const [isSaving, setIsSaving] = useState(false); function togglePlayback() { if (isSequencePlaying) { @@ -34,6 +36,22 @@ const ToolBar = ({ setBPM(e.target.value); } + async function saveTrack() { + setIsSaving(true); + try { + const blob = await renderSequenceToWav({ + sequence, + BPM: Number(BPM), + totalSteps, + totalBeats, + }); + const safeName = String(sequenceTitle).replace(/\s+/g, "_").toLowerCase(); + downloadBlob(blob, `${safeName}_${BPM}bpm.wav`); + } finally { + setIsSaving(false); + } + } + return (