I’m working on a music tracker. I’ve put enough hours into this that I think I should start documenting my experience. This is just for fun and I don’t expect the final product (if I even get to that point) to be something that anyone else would use, but maybe this info and my mistakes could be of interest to someone else.
I first discovered trackers in the late 1990’s, but didn’t really use them until 2017 after going through Brandon Walsh’s MilkyTracker tutorials on YouTube. (MilkyTracker is a free and multi-platform clone of the DOS-based FastTracker II, which I’ve never used.) My current aim for this is to use SDL for timing, mixing and file I/O, and Curses for the user interface, possibly migrating to a full SDL graphical window if it ever becomes a serious project. I’m writing in C, but might switch to another language in the future for safety and ease of development.
I started by following Rerwarwar’s public domain SDL2 audio tutorials. I have a callback and mixing function that can mix an arbitrary number of mono 16-bit samples to stereo with volume and constant power panning. The callback runs through one 16-beat sequence, and continues to loop until the program is closed. There is no UI to speak of, just some rudimentary NCurses draw calls to display the 16-beat sequence and the current row.
My first attempts at playing back a sequence of beats resulted in a very off-tempo rhythm. This is because I was trying to update the channel info directly from the main thread without any care for … timing. I moved the sequence-updating routine directly into the callback so that it can update the sound channels on a per-sample basis. While doing this, I introduced a pretty annoying click sound, which I spent longer than I care to admit hunting down. I was pretty frustrated, and rewrote most of the callback and mixer functions in the process of tracking down the culprit.
Just to satisfy my own curiosity, I implemented something like the MOD EFx effect on sample playback, then immediately removed it. In the MilkyTracker manual, this is described simply as “Funk it!” and it isn’t implemented at all. Digging further back, it’s described the same way in FastTracker II’s documentation, and also not implemented. What the heck is it? This ProTracker tutorial series by Wasp explains in depth, but to summarize: EFx incrementally inverts a sample during playback. It can make some really interesting sweeping sounds, but it also changes the source sample as a side effect of playing the music, so it’s understandable that subsequent trackers wouldn’t implement it. Forbidden effects. Anyways, curiosity satisfied, moving on.
That’s all I really have for now. I grabbed some old NCurses wrapper functions from another terminal project, and also discovered two very useful NCurses functions which I somehow missed earlier: nodelay(stdscr, TRUE) makes it so that the keyboard input function getch() doesn’t pause the main thread, and use_default_colors() prevents the library from disabling the transparency of your terminal. This is good news, because it appears that SDL_Event keyboard polling only works if a graphical window is created. In any case, I’d say the next action is to get a real interface up and running.
This has been stealing time away from Project Bolero, which I intend to get back to making weekly devlogs for on June 2nd. So, I probably won’t be working on this much in the short term, unless I get completely obsessed. It’s beginning to feel like I might be able to pull it off, and that’s exciting. Trackers are fun!
I uploaded some audio I recorded while troubleshooting to SoundCloud.