I've gotten far enough that I think it is presentable to others:
https://github.com/mabersold/kotlin-protracker-demoI wanted to see if I could write a mod player, and I wanted to do it in Kotlin. This is the result. My goal was to get it to play one specific song: Space Debris (included with the code, no command line arguments needed). I also had a secondary goal of making the code as easy-to-understand as possible (looking at other github repos, I noticed that it was pretty common to have zero explanation for how the code worked - I wanted mine to be well documented).
My resampling algorithm was basically to calculate a "step" variable (a double) and continually add to an index reference to find the correct index in an instrument's audio data array. It also calculates how many steps before it will reach the next index, and does a simple slope calculation to interpolate. Because it always reduces the period relative to the base instrument audio data, I do not implement any anti-aliasing.
I should note that I only implemented enough to play one specific song. Any features that were not used for this song were not implemented, such as fine-tuning, arpeggio effect, and others.
For the most part this seems to work pretty well. I'm not sure my vibrato implementation is 100% correct, but it sounds good, at least. I also start playing all instruments at index 2, rather than index 0, because I read in the various documents that the first two bytes are actually supposed to be looping data - not sure if this is what I should have done, but it sounds fine.
Additional note: in the code and documentation, I use the word "sample" only to refer to the individual elements of a PCM stream, not the instruments. This is to avoid confusion and to not overload the word "sample."
A few ways this player could be modified:
-Implement remaining ProTracker features
-
Change the audio generator to retrieve more than one sample at a time-Identify and remove unnecessary calculations
-Use coroutines while generating audio, or sending it to output (Kotlin implementation of threading)
-Resample to 16-bit instead of 8-bit (probably not necessary unless I want to support other formats that use 16-bit instruments)
-
Extract constants out to separate file-Global volume control
-Reduce stereo panning separation
-General reorganization, refactoring, and documentation improvements
Enjoy. Any feedback is appreciated (keeping in mind that this is a demo, not an actual product).