This is a rough list of tasks that should be completed to consider this project "done"
The Metronome
is the heart of the app. The BPM, measure, current tick, and time signature should be synchronized to all the components. The metronome will probably be a Context, accessed via a hook that returns a Reader and Writer
- create context #3
- add hook to return Writer and Reader #3
- Reader must be able to read #3
- current tick
- measure
- BPM
- time signature
- Writer must be able to set #3
- BPM
- time signature
- measure count
-
when Writer updates Metronome, current tick and measure reset to 0decided this is not important - Metronome Component must use Writer to set properties #3
- Metronome Component must use Reader to display properties #3
- Metronome must play an audible click on each tick #4
- Metronome must initialize as "stopped", and can be "started" by user input #4
- Metronome can be muted, while still running #11
-
move "playing" state into MetronomeControls; there is no obvious need for it to live in Metronomeirrelevant after #28
A Scene
is a collection of one or more Tracks. All Tracks in a Scene are synchronized to the same length.
- Component has one or more Tracks #5
- Component can add Tracks #5
-
Component can remove Tracksmoving functionality toTrack
#5 - Component has x-axis that visually corresponds to the time signature and measure count
- Component has a vertical line that tracks the current tick/current measure
- global lock prevents recording multiple tracks at once
A Track
is a single mono or stereo audio buffer that contains audio data. A Track
can be armed for recording, de-armed, muted, and unmuted. By default, the audio data in a Track
will loop indefinitely. The audio data in a Track
can be cleared.
- create Component #5
- shape: rectangle. Spans width of
Scene
- shape: rectangle. Spans width of
- Component can remove itself from scene #5
- Component has arm toggle button #8
-
audio data can be cleared from component without deleting it (to preserve track name)just mute, and then re-record if desired -
regression
allow re-recording audio over a track regression introduced here #34 - deleting a track stops playback #13
- Component can record data from user device #8
- Component shows waveform of recorded audio #20
- Component can adjust volume of playback #13
- Component has mute toggle button #13
- Audio input can be monitored, or not #13
- When Component is armed for recording, audio data is recorded starting at the beginning of the next loop, and automatically stops at the beginning of the following loop #9
- recording accounts for audio latency #12
- Component gets confirmation before deleting track #15
- Fix Recording button styling/class (use Tailwind) #15
- Ensure the audio buffer is always exactly as long as it needs to be to fill the loop #23
- clean up functionality from recorder worklet that isn't being used (might want to hold off until I know how visualization will work) #20
- Stems can be exported #26
-
Bounced master can be exportednot entirely sure what my goal was here... - Live performance can be saved and exported #37
- Keyboard shortcuts are added for most common actions #24
-
1
,2
,3
, etc select a track - once a track is selected,
r
toggles "armed for recording",m
toggles mute -
space
is play/pause
-
- add "tap tempo" functionlity and bind to
t
key #32
- flesh out header (add links to blog, etc) #16
- track page views (done automatically through Cloudflare)
- OG tags, SEO #16
-
Bug
: using keyboard shortcuts is causing weird recording artifacts... 😭 #30 - clean up "start" button/view
- Allow user to change inputs #25
- clean up TODOs #32
- show alert to user if latency cannot be detected due to their environment
- ~show alert if track latency cannot be detected, or if it seems wildly out of the norm (
100ms +/ 20ms ???). Consider adding a "custom latency" input option???punting on this until I see the demand - remove useInterval hook (not used)
- investigate network calls to workers. #21
- keyboard bindings should respect certain boundaries. For example, renaming tracks causes all sorts of things to fire, e.g.
a
,m
,r
,c
all do things that probably shouldn't happen. #29
- Use brand colors for range inputs
- Use brand colors for all colors! #36
- Add dark mode capabilities (honor system preferences)
-
Add dark mode toggle buttonrespecting system preferences should be sufficient - allow Track to wrap (controls top, waveform bottom)
- make Track controls slightly less wide
- add track ID indicator so keyboard controls make sense
- make beat counter sticky so you can see it even when you scroll
- allow changing tempo by typing value into an input
- add workbox so PWA can be installed #36
- is it possible to pass a Worker port to an AudioWorklet? If so, refactor so the app doesn't need to interact with the Waveform worker at all (currently app acts as a proxy between the Recording Processor and the Waveform worker)
- no, not possible
- add a "quantize" function
- bonus challenge: implement this using a WASM module inside a Worker (https://github.com/peter-suggate/wasm-audio-app)
- add manual echo cancellation (this will need to be a worker for sure, it is going to be a beefy algorithm)