Show HN: A 64-step drum sequencer I built using React and Redux
sequencer64.com
sequencer64.com
With this app I aimed to create an intuitive and usable drum sequencer that would run in the browser . I’ve always wanted to be able to program beats longer than 16 notes and see each instrument playing at the same time.
It’s built using React, Redux, and a fabulous web audio library called Tone.js.
This is the capstone to my learning to code which started in sept 2020. I was thrilled to be able to build something that combined my history in drumming and music production.
Happy to answer any questions!
EDIT: Link sharing was not working right but has been resolved. Share your beats! (You will have to re-save to generate a new url)
EDIT: Part I of the article is live: https://drumnickydrum.medium.com/from-funk-to-functions-da86...
Error: Media Recorder API is not available in debug.ts
and nothing ends up rendering, all divs are empty.(editing to add, since I can't reply to the child for some reason):
Mojave, safari 14.1
safari 14.1 in Mojave. I spend too much time with weird audio stuff to move past Mojave on this laptop unfortunately.
edit:
aha -> looks like you have to turn on the experimental features to get it to work. might be good to have a note for someone who doesn't have that turned on to avoid the black screen.
Safari Version 14.0.2 (16610.3.7.1.9)
MacOS Big Sur 11.1
2021 iMac (8-Core Intel Core i7 3.8 GHz)
Keep up the good work !
Consider having the space bar toggle playback - would make it so much smoother to use! (used to that from all kinds of music software)
I also wish I could save a pattern as a long link. (MIDI slave sync support would also be nice, but I’m not sure browser sound libraries support that)
After typing in “no”, reading the screen, then hitting the space bar, one will see a “>”. At this point, type in “save”.
The link for the game now is much longer, because it includes the entire state of the game in it, i.e.: http://iplayif.com/?story=http%3A%2F%2Fwww.ifarchive.org%2Fi...
<ValhallaSupermassive pluginVersion="1.0.0" presetName="Big Swell" Mix="1.0" DelaySync="0.25" DelayNote="0.2857142984867096" Delay_Ms="0.8399999737739563" DelayWarp="0.5" Clear="1.0" Feedback="0.75" Density="1.0" Width="1.0" LowCut="0.0" HighCut="1.0" ModRate="0.2738341093063354" ModDepth="0.4000000059604645" Mode="0.1666666716337204" Reserved1="0.0" Reserved2="0.0" Reserved3="0.0" Reserved4="0.0"/>
Sigh. Ever read an early proposal and think "wow, that's such a bad idea - good thing no one will pick up that"? Very not safe - a young naive me thought that reading early CGI, with its short urls passed on command-line, rather than longer urls on stdin. But people lycosed, and found a page, and were guided by it, and it spread, and... became assumed. Oh well.
Here in the future, with IE gone, IIRC browsers permit 80k, bottlenecked on Safari. Base-64 drops thats towards 60k. Of compressed data. Bzip can do a lot, even with JSON. Especially if you help it out.
There's some robustness cost, with unhappy security gateways and such, but for apps where featureful trumps reliable, we're no longer quite so crippled. Yay.
I can't say what exactly is next for the app. My top priority right now is to get hired as an engineer, and I built this to hone my skills.
My career as a musician came to a standstill last March and I feel I'm now ready to enter the software arena.
Open Source usually implies a license, e.g. (reductively) the MIT ("do whatever you want as long as you credit me"), GPL ("If you use this code, you also have to share your code"), etc.
Check out https://choosealicense.com/ for more info.
I wrapped the entire mess up into an easily called script, and I love it despite the horrors of its internals.
Anyway, awkward videos aside, if you want a contact in senior tech roles who was also a professional drummer, feel free to get in touch.
Username is same across most social media, and hn at username .com is my email.
edit: since you came up with this project with less than 1 year of learning how to code, I'm very curious about your music.
Some dnb fun (174bpm), nifty to see how useful a fresh look can be uniquely effective with the tools of the days.
I've tried helping career-stuck people learning to code and build apps, but I've found it difficult teaching them everything from the ground up.
As a mostly self taught developer, I do believe it's just matter of dedication and sheer will though, and thank you for proving that right.
There is no magic going on. If something works or doesn’t work, it’s in the code.
I think successful musicians already know this struggle so luckily I kept struggling through the hard parts.
Love the analogy, it does feel like that with music indeed!
I hope you can keep working in the music space; this level of polish is sorely needed. Fantastic job, drumnickydrum; and thank you for sharing!
I'm getting highly inconsistent note timings, with intermittent full 1-second pauses with no new notes being triggered. (FWIW, I also saw something similar in https://news.ycombinator.com/item?id=26870666 , and am getting choppy audio in Zoom that disappears as soon as I enable profiling...)
Is it my browser's fault for having the JS event loop stall, or the page's fault for driving audio off the page's event loop? Or both? (IDK how to fix Firefox, other than increasing the content processes above 3, which will reduce cross-tab lag but possibly increase RAM, or to reduce my extensions or find the one at fault.)
On a related note, how critical is it to follow the "audio on a real-time thread" dogma (http://www.rossbencina.com/code/real-time-audio-programming-...)? I've heard that not using Electron, writing real-time code, avoiding mutexes and allocations, mlock to avoid swapping, tuning OSes and picking processors and audio interfaces based on its low-latency properties, etc. is important for live performances, but not necessary for MIDI instrument input for (casual home users? studio work?).
It would be a fun challenge for me to programmatically figure out if the user is experiencing issues and disabled features to improve performance...
I think the flows of React and Redux are just not built for timing-sensitive applications like these. A lot of allocations and deallocations are taking place without any user input. Looking at the source code, the many selectors and other hooks probably has something to do with that.
Redux is also very explicit about treating objects as immutable, causing a lot of duplication as a result. For a simple web application this shouldn't be too much of a problem but again, this application is very sensitive to timing issues where 50ms of GC can cause a noticeable performance degradation.
It's not that the code is bad, it seems quite well memo-ised to get decent performance; I think it's a result of using the wrong too for the job, nothing more. Quite impressive that a framework as heavy as React can be made this responsive in my opinion.
If you run into any memory troubles, check about:performance and about:memory, you may be able to find what's causing the memory leaks.
I might try about:performance more, but in the past I recall it being similarly almost useless for pinpointing sites eating CPU.
https://www.html5rocks.com/en/tutorials/audio/scheduling/ is an article written by my former fellow co-editor of the Web Audio API specification, that talks in length about this.
In 2021, with the AudioWorklet [0] being available in all major browsers (including Safari as of a few weeks ago!), arbitrary computations can happen on the real-time audio thread. It is now possible to send a copy of the sequencer data (which note when, what sample, what velocity, etc.) to the real-time thread, and let it play, unaffected by the load of the machine, be it from the browser or other programs (until everything breaks down because you're also overloading the audio thread).
I think this app is very good and does the best it can under the programming model it's using, considering the environment it's being run in, but if more robustness is needed, there is now a way !
On your last paragraph, it is still _absolutely_ critical. An audio software that doesn't use a real-time thread for rendering cannot render audio without glitches, even under no load, even on a fast machine. You don't need to tune the OS [1] and pick special hardware these days: today's computers (and even computers from 10 years ago or older) are perfectly capable or running reasonably complex audio processing workloads _if the software is written correctly_. This is regardless of the use case. When we disabled the real-time thread on Windows by mistake in Firefox (adjusting priority of the process level, and then that was inherited to all threads, very quickly reverted), we had reports in a matter of _days_ (if not the next day), and the Firefox Nightly population is not that big. This was I think playing regular videos on social media, not even anything complicated.
If the author of the app, or anybody, wants to profile the app with the right tools, I've written a blog post [2] about this as well. I hear this tooling is used by audio professionals, now, and that they're happy with it. Happy to hear about any suggestion though :-).
For your Firefox-specific question, you're right that increasing the content process count will make everything better, and we're constantly improving memory usage so that it's possible to do so even on lower-specs machines, maybe it's worth a try. Please look at the "resident memory" values, and not, say, virtual or shared, because we make heavy use of shared memory and copy on write facilities of the OS to limit the memory usage when using multiple process (which we need to do for origin isolation and avoiding Spectre issues and sandboxing various bits of the browser as hard as we can, for example).
[0]: https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkle...
[1]: (but you can to improve robustness further, and it helps to have good drivers, such as Jack on Linux, WASAPI with MMCSS on Windows or ASIO, or just the normal stuff on macOS)
[2]: https://blog.paul.cx/post/profiling-firefox-real-time-media-...
Although a big contributor for performance issues in my project (and especially OP's) is the amount of UI updates that need to happen in succession (lots of event listeners, css transformations and dom changes)
On the topic of MMCSS, RtAudio is another real-time audio API... except the WASAPI backend had broken real-time thread scheduling (AvSetMmThreadCharacteristicsW, I think this is MMCSS?) on any builds with UNICODE enabled... and somehow literally nobody noticed, until I analyzed RtAudio under Process Monitor and wondered why it was trying to open a random Chinese string as a DLL file. I ended up fixing it at https://github.com/thestk/rtaudio/pull/292/files .
I don't know what that means. Is MMCSS not that important (even though you mentioned missing MMCSS caused severe stuttering in Firefox)? Is RtAudio under-tested/amateurish to the point people didn't notice it was stuttering more than it should be?
I assume it's unacceptable to synthesize (or probably time) audio off the main thread. How bad is it to use mutexes and allocations on the audio thread?
It is acceptable to do audio work off the main thread (as long as buffering is in place to prevent glitches from scheduling delays, and it's prioritized appropriately), but maybe you mean "on the main thread". In this case, it's not really recommended, but sometimes, it's what you need to do, for example when emulating an old console where everything is synchronous in the render loop.
Locks and allocations are best avoided, but modern locks and allocators are amazing. If the lock is _not contended_, it's very fast, and it's fine. If the allocation comes from a thread-local pool (some allocators do that), it's also very fast and fine, but that needs to be true across OSes, etc. for us. In other case, which is most of the time, it's best to avoid those.
We're not allocation nor lock-free entirely in Firefox though, but it's been thoroughly profiled - when know what we'll optimize when it's time to do so, but for now it's fine under extremely heavy load in a normal situation (we have locks when the audio devices are unplugged for an example of a "non-normal" situation). This is largely due to legacy (the Web Audio API, for example, is about 10 years old).
Thankfully the timing is handled by the Tone.js framework. It allows you to sync events with a callback function which passes in a 'time' argument that keeps everything in line.
Do you still gig?
Be sure to post it back here when you publish and also link to it from your Github repo (in case it doesn't land on the front page of HN).
I've been playing around with simply building a metronome using nothing but native JS and it's a chore. I'll have to check out Tone.js.
Great work!
The interface is also begging to be used in both directions: it feels like I should be able to click on a square in the sequencer and see the instruments light up on the right, so that I can change multiple instruments at a time for a given square!
Re: pitch/velocity. Yes! Just toggle “apply all”. You set the value then tap or slide over cells to edit individually.
This section was a pain to figure out and there’s def room for improvement.
sequencer64.com/sequencer/609b496c86fd88ad6d31e43c
The share UI might need a UI tweak as well -- if you save locally without login first, then login, you see your track but can't AFAICT generate a share URL.
Excellent work. Expand the sound library, include a good host of examples, wrap this up as an app, publish, and profit my friend.
Kudos, and congratulations on your success in advance!
Also, the animation speed switching between the “menu” ans the play/pause controls feels really slow. Not sure if these are just on my phone. :-)
It worked perfectly for me in ios safari... one of the most hostile environments for web audio!
The slice feature is awesome.
Works really well as a PWA
The bpm input could do with a stepper button for the lazy
attention to detail throughout is fantastic... well done!
Anyway, what I missed in your app was a method to use the keyboard to play the drums. Using the touchpad is too slow.
It was designed mobile first where I find the input to be very fast, but yes, on desk/lap the buttons are way slow.
It's a pwa, so make sure you close every tab and refresh a few times so the changes take effect.
If this doesn’t happen automatically edit the url. Sorry... Very weird.
The HN article link is the http url, that was the problem. If the http request is blocked, it never reaches the server to get redirected to the https version.
How do you find the transition into software development so far?
It was an extreme challenge to make this thing work cross-browser/os/device. I may look into some performance diagnostics if playback isn't great for enough users. Thx for the report.