In this tool-assisted programming video I create a synthesizer from scratch. It plays authentic Cave Story (洞窟物語) music tracks and sound effects (ORG and PXT files).
All resources concerning this video can be downloaded from http://bisqwit.iki.fi/jutut/kuvat/programming_examples/doukutsu-org/ , including the patch that does the waveform visualization.
Note there's a small bug in the showcased program regarding pitch calculation. It appears to work only when the sample rate is 48000. The formula for calculating "scale" for the lanczos filtering was also wrong; it used "phaseacc" when it should have used "phaseinc". The version on the web page has both bugs fixed.
The music system -- called Organya -- works like this. The song has 16 channels, eight of which are for melodic instruments and the other eight are for drums only.
Each channel is assigned one instrument, which is defined in the song header, and cannot be changed during the song.
Each channel can have a maximum of 1 voice playing simultaneously.
There is a global "wave table", which is hardcoded into the game; the wave table contains 100 short wave samples; the instruments refer to this wave table.
The actual song data is a per-channel list of events. Each event can begin a note, which plays for duration, or it can change the amplitude of the sample playing on the channel, or it can change the pan level, or do all of above.
In this program I play the music through ALSA sound system in Linux. For no reason at all, the audio data is going to be floating-point as opposed to the more commonly used sixteen-bit or eight-bit integer audio.
All the background music, in this video, is actually played through the program that I am writing in this very video. The background music played during programming is composed by Motoi Sakuraba, and originally published in Tales of Phantasia and Star Ocean SNES games. I converted those music tracks into Organya songs (covers).
The in-game songs I play are:
-- 3:56 Bush Lands (note: Grasstown is a mistranslation; note: played here without percussion)
-- 8:21 Jenka (note: it's a Finnish folk dance type, letkajenkka)
-- 8:59 Outside (the song that plays in the scene where you might choose to get the "bad ending")
-- 10:59 Gestation (the "default" exploration theme that plays in the beginning)
-- 12:36 Geothermal (this plays on the entrance of the first major boss, where the plot too begins branching significantly: it decides what happens to miss Curly Brace.)
-- 14:26 Pulse (demonstrating the detuned instruments; waveform is of "safety" though)
-- 14:55 Fanfare 1 (acquiring an item)
I do some tool-assisted voiceover in the video. I had fun doing that, not taking my cumbersome pronunciation too seriously. I hope you won't, either. All is fair in teaching memorably. Well, I _cannot_ take it too seriously. English is very difficult to pronounce for me, very difficult sequences of consonants and sometimes hard to choose the right phonemes to begin with. In Finnish, my native language, having more than two consonants in a row is very rare, and even when there are two, the possible combinations are very few. I have been training my English pronounciation for years, but the entire language is a tongue-twister for someone with this background. I have found Hebrew and Japanese to be significantly easier.
Anyway, does anyone want to contribute closed-captions?
Quick illustrations of each modulation method (each generates 8-bit mono PCM audio):
No modulation example code:
(add relevant #includes)
int main() { float p=0;for(;;) { float a = sin(p); putc(128 + 100*a); p += 0.1; } }
Amplitude modulation is like this: The level of one signal is multiplied by the level of the second signal. Example code below:
int main() { float p=0,p2=0;for(;;) { float a = sin(p), b = sin(p2); putc(128 + 100*a*b); p += 0.1; p2 += 0.01;} }
Frequency modulation is like this: The frequency of one signal is changed by the level of the second signal. Example code below:
int main() { float p=0,p2=0;for(;;) { float a = sin(p), b = sin(p2); putc(128 + 100*a); p += 0.1 * (1+b/9); p2 += 0.1;} }
Interesting, although I have to admit mostly over my head. I can do programming, but only with great difficulty, and I don't know much about audio encoding so I couldn't really follow what you were doing very well. But it looks most impressive. I wish I had the mental tenacity to do stuff like this.
By the way, don't worry about your English pronunciation, it was perfectly understandable :)
JimPlaysGames 2 weeks ago
@JimPlaysGames Thanks Jim! I wish to instigate inspiration and insights. A lesson is at its best when it provides both something familiar and something alien to audience of all skill levels, clearly identifying possible next steps. I don't know how well I did in that regard, but at least I did lay out some concepts. I have been planning to make a lesson on how PCM audio works in general, but I can't figure out how to make that kind of a presentation. So I covered some of it in narration instead.
Bisqwit 2 weeks ago
Lolwut!? I get 50 errors and 10 warnings when trying to compile!
I just wanted an Organya player for Linux because I can't find one anywhere, and I don't have enough skills.
What is that thing you write it with?
ZLau13 3 weeks ago
@ZLau13 Do not forget the -std=c++0x flag, I said in the video at 3:41. Without that flag, it fails to compile, because for now GCC defaults to pre-C++0x.
Bisqwit 3 weeks ago
I somehow knew you're Finnish before checking from your channel.
And isn't "Outside" actually named "Moonsong"?
ZLau13 2 months ago
@ZLau13 Maybe, but in the game's EXE it is just "oside".
Bisqwit 2 months ago