Skip to content

Commit

Permalink
feat: Record & Repeat buttons, region button rework (#3)
Browse files Browse the repository at this point in the history
- Added toggle record button to 
- Added toggle repeat button to 
- Reworked region/song button - added region index, current time in seconds, and in beats over the track
- Changed font in a label for db to monospace
  • Loading branch information
nikarh committed Feb 9, 2024
1 parent 8e31603 commit 349a407
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 64 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
dist
dist
media
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ The example project has some more tracks so here is a brief explanation of their
- The input group is for tracks having a physical input source, like a guitar or a microphone. If any additional processing is needed (compression, eq, reverb), it should be put on these tracks
- The output group is for tracks with physical outputs. All of these tracks have plugins for basic hearing safety - a `-10 dB` gain and a brick-wall limiter at `0 dB`. These tracks have "Receives" from input group tracks and audio group tracks.


## Notes

When a specific song (region) is selected from the UI, it selects the region and sets the cursor to the beginning of the region. Selecting the region allows stopping the playback automatically when the region ends. For REAPER to stop the playback automatically you need to check `Preferences` -> `Audio` -> `Playback` -> `[x] Stop playback at end of loop if repeat is disabled.` and disable repeat in your project.
Binary file modified screenshots/Web - Control.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/Web - Mix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Icons } from "./Components/UI/Icons";
import { BottomNavigation } from "./Components/UI/BottomNavigation";

const SUBSCRIPTIONS = [
{ request: "TRANSPORT", interval: 2000 },
{ request: "TRANSPORT", interval: 100 },
// Query every 100ms for peak levels
{ request: "TRACK", interval: 100 },
{ request: "REGION", interval: 4000 },
Expand Down
77 changes: 49 additions & 28 deletions src/Components/Control/Playback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,57 @@ import { Icons } from "../UI/Icons";

export function MainControl() {
const {
data: { playState: state },
actions: { play, pause, stop },
data: { playState: state, recording, repeat },
actions: { play, pause, stop, record, toggleRepeat },
} = useReaper();

return (
<div class="flex justify-center rounded-md shadow-sm" role="group">
<button
type="button"
onClick={play}
class={`btn-primary rounded-l w-16 ${
state() == PlayState.Playing && "selected"
}`}
>
{Icons.Play}
</button>
<button
type="button"
onClick={pause}
class={`btn-primary w-16 ${state() == PlayState.Paused && "selected"}`}
>
{Icons.Pause}
</button>
<button
type="button"
onClick={stop}
class={`btn-primary w-16 rounded-r ${
state() == PlayState.Stopped && "selected"
}`}
>
{Icons.Stop}
</button>
<div class="flex justify-center space-x-4">
<div class="flex justify-center rounded-md shadow-sm" role="group">
<button
type="button"
onClick={play}
class={`btn-primary rounded-l w-14 ${
state() == PlayState.Playing && "selected"
}`}
>
{Icons.Play}
</button>
<button
type="button"
onClick={pause}
class={`btn-primary w-14 ${state() == PlayState.Paused && "selected"}`}
>
{Icons.Pause}
</button>
<button
type="button"
onClick={stop}
class={`btn-primary w-14 rounded-r ${
state() == PlayState.Stopped && "selected"
}`}
>
{Icons.Stop}
</button>
</div>

<div class="flex justify-center rounded-md shadow-sm" role="group">
<button
type="button"
onClick={record}
class={`btn-primary btn-primary-red w-14 rounded-l ${recording() && "selected"}`}
>
{Icons.Record}
</button>

<button
type="button"
onClick={toggleRepeat}
class={`btn-primary w-14 rounded-r ${repeat() && "selected"}`}
>
{Icons.Repeat}
</button>
</div>
</div>
);
}
64 changes: 45 additions & 19 deletions src/Components/Control/Regions.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
import { createSelector, For } from "solid-js";
import { useReaper } from "../../Data/Context";
import { Region } from "../../Data/State";
import { CurrentTime, Region } from "../../Data/State";

function Progress(p: { progress: number }) {
function progress(region: Region, currentTime: number): number {
return Math.max(
0,
Math.min(
100,
((currentTime - region.startTime) / (region.endTime - region.startTime)) *
100,
),
);
}

function time(totalSeconds: number): string {
if (totalSeconds < 1) {
return "0:00";
}
const minutes = Math.floor(totalSeconds / 60);
const seconds = Math.floor(totalSeconds % 60);

return `${minutes}:${seconds.toString().padStart(2, "0")}`;
}

function Progress(p: { region: Region; currentTime: CurrentTime }) {
return (
<div
class="absolute bottom-0 left-0 top-0 bg-gray-400 opacity-25"
style={`width: ${p.progress}%`}
/>
<>
<div
class="absolute bottom-0 left-0 top-0 right-0 bg-gray-400 opacity-25"
style={`width: ${progress(p.region, p.currentTime.seconds)}%`}
/>

<div class="absolute top-0 bottom-0 right-0 flex items-center opacity-70 px-3">
<p class="text-xs text-gray-400 bg-neutral-900/40 rounded-lg p-1 font-mono">
{time(p.currentTime.seconds)} / {p.currentTime.beats}
</p>
</div>
</>
);
}

Expand All @@ -19,18 +48,10 @@ export function Regions() {

const isPlaying = createSelector(
currentTime,
(r: Region, t) => t >= Math.floor(r.startTime) && t <= Math.ceil(r.endTime),
(r: Region, { seconds: t }) =>
t >= Math.floor(r.startTime) && t <= Math.ceil(r.endTime),
);

const progress = (r: Region) =>
Math.max(
0,
Math.min(
100,
((currentTime() - r.startTime) / (r.endTime - r.startTime)) * 100,
),
);

return (
<div>
<h2 class="mb-2 text-m font-extrabold leading-none tracking-tight text-gray-900 dark:text-white">
Expand All @@ -41,13 +62,18 @@ export function Regions() {
{(region) => (
<button
type="button"
class={`relative overflow-clip btn-outlined my-1 px-5 ${
class={`relative grow flex h-10 overflow-clip btn-outlined my-1 px-3 ${
isPlaying(region) && "selected"
}`}
onClick={() => moveToRegion(region)}
>
{isPlaying(region) && <Progress progress={progress(region)} />}
<span class="relative">{region.name}</span>
{isPlaying(region) && (
<Progress region={region} currentTime={currentTime()} />
)}

<span class="relative">
{region.id}. {region.name}
</span>
</button>
)}
</For>
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Mix/SendControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function Slider(p: SliderProps) {
<p
class={`text-xs text-white ${
input() != null ? "text-gray-400" : ""
} bg-neutral-900/40 rounded-lg p-1`}
} bg-neutral-900/40 rounded-lg p-1 font-mono`}
>
{input() == null && normalizedToDb(p.value).toFixed(2)}
{input() != null && normalizedToDb(input() ?? 0).toFixed(2)} dB
Expand Down
34 changes: 34 additions & 0 deletions src/Components/UI/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,38 @@ const Stop = (
</svg>
);

const Repeat = (
<svg
xmlns="http:https://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"
/>
</svg>
);

const Record = (
<svg
xmlns="http:https://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width={1.5}
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 18.75a6 6 0 0 0 6-6v-1.5m-6 7.5a6 6 0 0 1-6-6v-1.5m6 7.5v3.75m-3.75 0h7.5M12 15.75a3 3 0 0 1-3-3V4.5a3 3 0 1 1 6 0v8.25a3 3 0 0 1-3 3Z"
/>
</svg>
);

const Control = (p: { class?: string }) => (
<svg
class={`w-6 h-6 mb-1 ${p.class}`}
Expand Down Expand Up @@ -89,6 +121,8 @@ export const Icons = {
Play,
Pause,
Stop,
Repeat,
Record,

Control,
Mix,
Expand Down
23 changes: 21 additions & 2 deletions src/Data/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ interface PauseAction {
interface StopAction {
type: "Stop";
}
interface RecordAction {
type: "Record";
}

interface MoveAction {
type: "Move";
Expand All @@ -33,18 +36,25 @@ interface ToggleSendMuteAction {
send: string;
}

interface ToggleRepeatAction {
type: "ToggleRepeat";
}

export type Action =
| PlayAction
| PauseAction
| StopAction
| RecordAction
| MoveAction
| SetTrackVolumeAction
| SetSendVolumeAction
| ToggleSendMuteAction;
| ToggleSendMuteAction
| ToggleRepeatAction;

export function reduceActions(actions: Action[]): Action[] {
let control: (PlayAction | PauseAction | StopAction)[] = [];
let control: (PlayAction | PauseAction | StopAction | RecordAction)[] = [];
let move: MoveAction[] = [];
let repeat: ToggleRepeatAction[] = [];
let trackVolume: { [k in number]: SetTrackVolumeAction } = {};
let sendVolume: { [k in number]: { [k in string]: SetSendVolumeAction } } =
{};
Expand All @@ -55,11 +65,15 @@ export function reduceActions(actions: Action[]): Action[] {
case "Play":
case "Pause":
case "Stop":
case "Record":
control = [action];
break;
case "Move":
move = [action];
break;
case "ToggleRepeat":
repeat = [action];
break;
case "SetTrackVolume":
trackVolume[action.track] = action;
break;
Expand All @@ -80,6 +94,7 @@ export function reduceActions(actions: Action[]): Action[] {
return [
...control,
...move,
...repeat,
...Object.values(trackVolume),
...Object.values(sendVolume).flatMap((s) => Object.values(s)),
...Object.entries(sendMutes).flatMap(([track, sends]) =>
Expand Down Expand Up @@ -107,6 +122,10 @@ export function actionsToCommands(actions: Action[]): string {
return "1008;TRANSPORT";
case "Stop":
return "40667;TRANSPORT";
case "Record":
return "1013;TRANSPORT";
case "ToggleRepeat":
return "1068;TRANSPORT";
case "Move":
return `SET/POS/${action.end};40626;SET/POS/${action.pos};40625;TRANSPORT`;
case "SetTrackVolume":
Expand Down
Loading

0 comments on commit 349a407

Please sign in to comment.