Status Updates posted by Remilia Scarlet
So I'm finally getting around to doing something I've planned to do for ages: a small update to my Shadows of The Nightmare Realm level set. The changes are all finished, I just want to play through it a few more times to test things out before I upload it. I also want to record official playthroughs of all the levels before I release it. So probably in a week or two.
* The ZScript in it has been converted to DECORATE. It now works in both GZDoom and K8Vavoom.
* Some story retcons that I've been planning for years are finally in place. SoTNR was always meant to be part of a sort of personal mythology I have going, which also includes Umbra of Fate (its prequel), my Xala'noth level for Quake, Eschatology, The Unending, and I think a few others. It's still heavily Lovecraft inspired, it's just not using the Lovecraft mythos anymore.
* Small rebalancing tweaks here and there. Mainly a few extra stimpacks and a few extra rockets.
* Small lighting fixes in level 3.
* Texture alignment fixes in level 3.
* A few secrets are a tiny bit more obvious.
* The Archon of Hell's health was reduced from 2000 to 1650 so they don't feel quite so much like a bullet sponge (final health amount may change in the next few days).
* A spelling issue was fixed.
* A softlock on levels 1 and 4 in their tech areas was fixed (the areas in question use the same layout).
* Added a pillar to a room in level 2 so that the fight with the spider mastermind feels better and less stressful. Or maybe I'm just getting older and find things like that stressful anymore ^_^;
* Added a light in level 3 to make a switch more obvious.
* Reduced the absurd ceiling detail on the outside of level 3 that couldn't ever be seen properly anyway.
* The crusher trap in level 3 that people complained about is now a bit more obvious.
* Changed how I build the game to match how I do all my levels anymore: A Rakefile, command line utilities, and a standardized (for me, anyway) directory structure.
Something to keep in mind is that there are a few small lighting bugs with SoTNR in K8, and the performance absolutely tanks in a few areas when shadows (r_shadows) are enabled. This seems to be because of how I did lighting back then, which was much more inefficient than how I do it these days. But, it is totally playable in K8 and still runs at 60+ FPS for me in most places.
That being said, most people should probably use GZDoom to play it, but nothing says you have to anymore. I use K8 for it because I like how I can adjust the player's movement to feel like Quake, and the shadows :-P
So remember midi123, my command line MIDI player, and it's associated SoundFont synthesis library, Haematite? Both written in pure Crystal? Yeah, the code in the repo's tip now supports mmap()'ing of SoundFonts for vastly improved memory usage and (basically) streaming sample data from disk.
Playing a MIDI using my custom SC-55 SoundFont:
- before: 128 MB used
- after: 32 MB used after finish playing
More updates to the program coming soon. Gonna take a break from Benben and work in it instead.
My VGM player Benben v0.2.0 is out! New features include YM2612 and SN764xx support (so, Sega Genesis music now works), OPL and OPL2 support, greatly improved CPU and memory usage when rendering to WAV or Au, and various other things.
Full release notes, source code, and an x86-64 Linux AppImage, are all available here: https://chiselapp.com/user/MistressRemilia/repository/benben/technote?name=acb3dbf5feb1f957b7d1c84c8ac942d3e4b104b7
I'll see about possibly getting an AppImage for AArch64 out later today as well. The program works fine on my PineBook Pro and Raspberry Pis, so it's just a matter of packaging (or you compiling it from source).
Related, my underlying YunoSynth library is now at v0.2.0 as well: https://chiselapp.com/user/MistressRemilia/repository/yunosynth/
Benben v0.1.0 is now out! This is the first release of my command line VGM music player written in Crystal. Think "vgmplay", but with more features (and pretty much identical performance).
Source code and an x86-64 Linux AppImage are here: https://chiselapp.com/user/MistressRemilia/repository/benben/technote?name=07c9c37c82d3feba1a46fa98ba67276cd2bccf0f
If you don't have any VGM files, you can some at https://vgmrips.net Just keep in mind that Benben supports many, but not all, of the chips right now (but it will!)
This uses my own VGM library, YunoSynth, which also has its first v0.1.0 release today: https://chiselapp.com/user/MistressRemilia/repository/yunosynth/
I added both a OKI MSM6295 emulator and a QSound emulator to YunoSynth recently, so even more VGM files are now supported. Then I started to work on an actual full-featured player called Benben, rather than relying on the bare-boned example player I wrote.
This is obviously similar to my midi123 program, except that it's for playing VGM files :-P It's also a lot lighter weight. Just like with midi123, you can load up multiple files (including from XSPF playlists), go forward and backwards in the list of files, see some VU meters, enable a few optional effects, etc. Code isn't 100% ready yet, but I'll probably get it up this week.
The program is named after https://en.touhouwiki.net/wiki/Benben_Tsukumo
The list of chips that YunoSynth is supporting is growing :3
- Hudson HuC6280, the sound chip PC Engine/Turbografx-16
- Konami K051649, aka Konami SCC+, used with the MSX2.
- General Instruments AY-1-8910 and similar, used in the MSX2 and a bunch of other systems.
- Namco C352, used for Soul Edge, SoulCalibur, Tekken games, etc.
- Sega MultiPCM, used for various Sega arcade games (DAYTONAAAAAAAA LET'S GO AWAY!)
- Yamaha YM2151, used in TONS of things. Two cores are technically available, but I haven't gotten the Nuked-OPM port working yet.
- OKI MSM6258, used in various things. But this + the YM2151 means X68000 VGMs play now.
Yamaha YMZ280B, used in various arcade boards, like DoDonPachi and Cyvern.
I'll probably add QSound next, then maybe some other PCM-y chips. Or I might do the YM2203 so I can listen to some of the older PC-98 Touhou soundtracks with my code.
Audio compression artifacts ahead because I can't be arsed to make a YouTube video right now: https://social.sdf.org/system/media_attachments/files/109/953/928/469/096/962/original/b11f6525415ab2a2.mp4
Here we go! YunoSynth is a fast VGM/VGZ playback library written in 100% native Crystal :D The chip emulators that are currently implemented are:
- Hudson HuC6280 (PC Engine/TurboGrafx-16)
- Konami K051649 (MSX2)
- General Instruments AY-1-8910 (various systems)
- Namco C352 (various arcade boards, like Soul Edge and Tekken)
More chips will be added soon ^_^
This is why I was working on that Lisp prototype recently ^_~
Very early WIP source code is here: https://chiselapp.com/user/MistressRemilia/repository/yunosynth
Note: The second song in the example video is a bit louder than the others. You've been warned.
A little something I've been playing with the past two days: PC Engine/TurboGrafx-16 music playback in 100% pure Common Lisp.
Still a tiny bit buggy, and there aren't any optimizations in place yet, but it's at least somewhat usable. I'm launching it from within my editor right here. This is the opening music from a SuperGrafx game called Aldynes (which is a fun shmup if you haven't played it).
I'll probably port this to Crystal once I clean up the structure and figure out some of the small bugs remaining.
Improved. I think I have most of the bugs in the PC Engine emulation squished now. The song this time is the main table theme from Devil's Crush, a BADASS pinball game for the PC Engine.
...ok, half of the MSX2 support is working now as well. It's lacking AY-1-8910 support right now, but the K051649 is implemented.
Song is the first stage from Space Manbow.
Been a while since I posted about midi123.
The code in the repo's trunk supports native MUS playback, XSPF playlists (and JSPF), PulseAudio as an alternative to PortAudio, a new reverb type (MVerb), reverb presets and full configurable parameters, and the ability to take an HTTP/HTTPS or Gemini URL and play a file straight from there. Still have some more to add for the next version, but that's what I've been up to.
Yay, midi123 v2.1.0 is done! As I mentioned before, this version adds support for multiple filter types, multiple reverb types, multiple interpolation modes for the chorus effect, a parametric EQ (now with an arbitrary number of bands), NRPN support, rendering to Au files, and a VU meter display. In the end I decided against including SysEx in v2.1.0 because I need to do some more thinking regarding some non-technical things with it. But the rest is all there.
There's also a new command line parameter, --plot-eq, that will print out a GnuPlot script to plot the parametric EQ. This might help you visualize the filter curve if you want to configure the EQ. The EQ can be enabled/disabled during playback with the "e" key.
Supported filters for MIDI channels (controllers 71/74) and the voices (SoundFont instruments):
- Standard 2-pole biquad lowpass
- CEM3394-like 4-pole lowpass
- SSM2040-like 4-pole lowpass
- EDP Wasp-like 2-pole lowpass
- Korg MS-20-like 4-pole lowpass
Source code, Linux AppImages for x86-64, and full release notes available here: https://chiselapp.com/user/MistressRemilia/repository/midi123/technote/814a0aacfd59ac972af6b2353cffc7129812937f
This is built using Haematite v0.3.1, my SoundFont synthesizer that's written in pure Crystal and based on MeltySynth; and RemiAudio v0.1.0, my general purpose audio library that's also written in pure Crystal.
Oh, and you can make it look gay with an environment variable. The default is just the normal text color. Have fun finding the values :D
Oh boy, midi123 (my command line MIDI player) and Haematite (my port of MeltySynth, a SoundFont synthesizer library) are getting a bunch of new features.
- Built-in 5-band equalizer in midi123. Band 1 is a low shelf, band 5 is a high shelf, and the others are normal peaking bands. The EQ is fully configurable from the config. It can be enabled/disabled in the config, on the command line, and while midi123 is playing by pressing the 'e' key.
Multiple reverb models are back in both Haematite and midi123. Choices, from highest quality to lowest:
- ZitaReverb, a port of Zita-Rev1, a high quality hall reverb
- ZitaReverbSimple, simplified very slightly for performance; almost identical in sound to normal ZitaReverb
- Schroeder, aka Freeverb
- Selectable lowpass filters for the voices in both Haematite and midi123. The SoundFont specs state that the filter should be a 12db (2-pole) filter, and then leaves the implementation up to the software author. Haematite and midi123 bend this rule a little bit. Both default to a 2-pole filter, but also support three additional filters: a 4-pole one based on that found in a CEM3394, a 4-pole one based on the SSM2040, and a 2-pole one that approximates the filter found in an EDP Wasp. midi123 lets you select these from the command line, or from the config.
- SysEx support (not yet committed to the repo) in Haematite. This lets you control the reverb type and state, the filter type, and the chorus state.
- NRPN support added to Haematite. Right now it does nothing (well, in the code in the repo, these currently control the reverb/chorus state), but this will let me add more control over the synthesis parameters in the future.
- Selectable interpolation modes for the chorus effect in both Haematite and midi123.
- Rendering to Au is now supported in midi123 (I think I'm the only one who cares about .au files lol)
- VU meter as an alternative to the progress bar when playing in midi123.
I still have some additional features planned, and some more work to do, in both for the next release, but I was too excited not to share.
Tonight's debauchery: Getting MP1, MP2, and MP3 files to decode to PCM natively with pure Common Lisp (no bindings!). I've got MP1 and MP2 working so far :D
MP3 decoding is currently giving me a floating point overflow because it's causing a few things to be either Infinity and NaN. Technically Common Lisp doesn't use IEEE 754. So I need to determine if the MP3 decoding has a bug and shouldn't be causing an infinity/NaN, or I need to find a workaround. I'm suspecting the former.
The rendering function is also putting out raw bytes right now, but I'll change that to output int16/float32 soon. As usual, my MO is to do the same thing in Crystal once I get this all working in Lisp.
midi123 v2.0.0 is now released! Downloads (Linux x86-64 AppImage) and a complete what's new here.
- The entire thing and its underlying library were rewritten in Crystal. It's now twice as fast and uses half the RAM.
- --loop is improved, and --speed added
- there's an optional stereo enhancer effect you can enable
- Config file support so you don't have to type parameters all the time.
I started a Crystal port of midi123 (using Haematite) just out of curiosity the other day. It's almost complete. Here's a very quick benchmark where I render a song (ROTT's "How'd I Do?") to CD-quality WAV:
Lisp midi123: == 450MB, 00:00:01.620355846 ==
Crystal midi123: == 113MB, 00:00:00.831384978 ==
Whew. Did not expect that. Both the Lisp and Crystal versions use my "RemiWAV" library for their respective languages to write the WAV, so this is pretty apples-to-apples.
Aww yeah, fixed the cubic interpolation bug... by removing it from the oscillator.
Instead, there's now proper oversampling in CL-MeltySynth/Haematite and midi123. From 1x (none, the default) to 32x (lol). The oversampling uses Hermite interpolation to generate the new samples that get placed between the original ones. I'll add more options for other methods soon. Yay for finding out about the "Elephant Paper".
There is a downside, though: oversampling takes place when the SoundFont data is loaded. Since the entire SoundFont is loaded into RAM, that means the entirety of the oversampled data gets stored in RAM. So the sc-55.sf2 that I always use (I dunno which SC-55 SoundFont it even is anymore, except that it's not trevor0402's) has about 103mb of PCM data at 44.1KHz. Without oversampling (aka, 1x), this is stored as 103mb in RAM. Oversampling 2x means that 207mb of PCM resides in RAM. 4x means 412mb is used. 32x... yeah.
So oversampling is basically a new performance knob you can tweak, where you balance memory usage vs quality.
But that's not all... SoundFonts usually use 16-bit signed integer for a sample format (and some use 24-bit I think, but I don't support them yet). You can also tell the library how you want to store the oversampled data, with options for Int16 (original), Float32, and Float64 (which is what it gets converted to during synthesis anyway). The interpolation functions all spit out 64-bit floating point samples, so converting those back to int16 (the default) incurs a very slight accuracy penalty. Using one of the two float formats uses more RAM, however. Without oversampling (aka, 1x) and using float64, my 103mb SC-55 soundfont is stored as 412mb in RAM. Oversampling 2x means that 824mb of PCM resides in RAM. 4x means 1648mb is used. 32x oversampling + float64 is about 12.9GB.
Of course, 32x + float64 is just absurd and not practical unless you want to show off :-P I don't see anything over 4x being useful, but I'll leave them in there because large numbers can be fun.
Sometime in the future I plan to still implement an option to load only the samples that are actually needed into RAM, but that's a long ways off, because that'll require a lot of planning and restructuring. That would, however, let you do 32x + float64 without needing a ton of RAM.
This is effectively another new performance knob you can tweak. I'm thinking actual end-user programs would just hide these two performance settings behind a generic "quality" setting, where quality 1 means 1x and Int16, while quality 20 (or whatever) would be 32x and Float64.
The good news? Almost no CPU impact during playback unless you turn oversampling up over 4x, and then it still isn't that big of a hit. Loading the SoundFont is a bit slower each time you go up in oversampling, but not by much, and that only has to happen once.
Anyway, the defaults of 1x and int16 storage, which is just like the original behavior.
So, I ported my CL-MeltySynth library to Crystal! It's called Haematite and the code is here. This library will let Crystal programs provide MIDI playback using SoundFonts.
CL-MeltySynth is itself a port of Sinshu's MeltySynth from C# to Common Lisp. Haematite came from CL-MeltySynth, so it's an indirect port of the original.
Haematite is 1:1 with CL-MeltySynth as far as features go, so it has the port of Zita-Rev1 for a reverb, multiple reverbs to chose from, the new chorus reminiscent of the Juno-60, dithered output, cubic interpolation, soft clipping, stereo enhancer, RMI support... all that good stuff.
Runtime performance is almost identical to the Common Lisp version on my desktop, and I expect only a slightly larger difference once I try it out on my laptop. I'm not sure if this says more about Crystal or SBCL ^_^; Either way, the difference is not enough to warrant rewriting midi123 in Crystal, so that program will remain written in Common Lisp. However, the memory usage of Haematite is quite reduced compared to Lisp since it doesn't have the huge runtime overhead.
Going forward, CL-MeltySynth will receive new features first, then I'll back-port them to Haematite.
- Show previous comments 1 more
Very nice to see yet another port of MeltySynth ^_^
Very nice to see yet another port of MeltySynth ^_^
素敵なプログラムを書けるのがありがとう! I really appreciate how easy it is to understand your code. I've tried to link back to MeltySynth whenever I can as a thank you gesture ^_^
I hope my Japanese isn't too rusty...Quote
Oh my! Slackware? You're one of those, huh! :p
Very interesting project, overall. You've implemented an astounding array of things, from reverb to modulation (though modulation.cr is a stub?...). I remember you talking about finishing up CL-MeltySynth not too long ago, you work fast! Props to you!
Yeah, I've used Slackware since 2002. All my computers (including my Raspberry Pis) run it exclusively.
modulator.cr (and modulator.lisp) just discard the modulator information from the SoundFont files. I forget exactly what this information is, but it doesn't seem like it's needed in order to produce good audio, at least with the SoundFont's that I've used. Maybe I'll add support for them in the future, though. For now, modulationenvelope.cr implements the actual envelope-based modulation, while lfo.cr provides an LFO for stuff like MIDI controller 1 and vibrato. It's not like Haematite or MeltySynth or CL-MeltySynth ignores modulation in MIDI files ^_^
I actually started Haematite before I did CL-MeltySynth, but I dropped it to do the Common Lisp version first since I use Lisp a lot more often. I also wanted to show that Common Lisp can indeed do high-performance code :-P
Debugging is also a lot easier in Lisp, and the code behaves more like I expect when it comes to numbers and math. With Crystal, I ended up fighting the compiler a lot because of how it handles number types. This was new to me, and was something I had to learn about as I went.
Now that I feel comfortable with how Crystal does numbers and math and autocasting, I was able go back to Haematite and finish it. I mostly just needed back-ported my changes to the Lisp version, then clean up the unfinished or buggy parts, and write the sample player. This sort of thing doesn't take me long since I don't have a job outside of being a housewife, so I can sit and program for most of the day ^_^ I forget how long the initial CL-MeltySynth port took, but it wasn't too long... maybe a week or two total?
I ported ManagedDoom to Crystal in about a month, iirc. That's actually where my idea of porting MeltySynth came from. My Crystal port of Doom isn't released, however, and probably won't ever be, because I can't find where the bugs are, and I suspect it's due more to language difference than typos.
I'm still adding to CL-MeltySynth and midi123. Tonight I replaced the chorus effect in CL-MeltySynth with one based on the unit in the Roland Juno-60. As an added bonus, this new chorus seems to actually perform slightly better than the old one.
First run = the original chorus inherited from MeltySynth.
Second run = the new chorus.
If anything, the new chorus makes the Warcraft 2 music sound even better and more like the CD, since that's one soundtrack I know of that actually uses controller 93 to set the channel chorus levels.
I'm hoping to add some NRPNs (if I understand them correctly) so that the synth's more unique aspects can be controlled from MIDI files next. And also controller 94 (effect 4), which on hardware synths seems to control either a phaser effect or a delay unit, depending on the synth. I think I used that controller way back in the day when I still used my Roland JV-1010 to make music, but it's been a long time.
I'm alive! I had a bit of a break from Doom. Everything is fine, I just needed time off from mapping and being social around here.
Praise Satan, The Dark Mother of Spooky Doom Aesthetics lives!
Hah, I knew the delay with the latest version of k8 could not have helped matters!
It has not, no ^_^; Still waiting on ticket 51480cab21. If I have time (and energy), I may try to patch it myself and then just submit a patch. It wouldn't be the first time I've submitted to K8, and it'd honestly be rather fun. Otherwise I'm in no rush, really. I have plenty of other stuff to work on for the time being.
I've been holding off on releasing Eschatology 2 (which is finished) due to a bug in the current K8Vavoom build that impacts it. The bug is minor - certain sound sequences aren't triggering, so some door-like things are silent - but it's important enough to me that I'm just going to wait. I think Ketmar mentioned something about going back to K8Vavoom in August or September, so it shouldn't be much longer anyway.
In the meantime, I'm just tinkering with some texture packs, programming, and attempting to not overheat.
Eschatology 2 will be delayed just a few days, probably like Sunday or so. I have mental health stuff going on, among other things ^_^;
So! Doom stuff!
As I sorta mentioned before, I'm splitting Eschatology up into multiple releases. This is being done mostly for mental health reasons, and partially so I can focus more on other hobbies, like programming and music. Here's how it'll work:
- Eschatology's story will be told over a series of individual releases, just like with Freaky Panties, but with a bit more emphasis on the story. Freaky Panties' story is kinda just background fluff that's almost non-existent ("Doomguy searching for his favorite pair of panties, which the demons stole"), but Eschatology's will be obvious (and more serious).
- Eschatology will have no start map. Each release is an individual pk3 that you load up and play. Just like Freaky Panties.
- Eschatology 1 ("esc01") will be out this coming week (!!!). It will include the map "Decayed Faith".
- Eschatology 2 ("esc02") will be out sometime between the 20th and 30th. It will have the map "Dismembered Doll Parts".
- Eschatology 3 ("esc03") will be out in the late fall or early winter, depending on my programming projects. It will be the map "Colombian Necktie", which is the one with the hellfire.
- Eschatology 4 ("esc04") will be out just before December, and will be the remixed/expanded version of Halls of The Goat Child.
- Eschatology 5 ("esc05") will be started on next year sometime.
- I'll try to slip in a Freaky Panties map or another non-Eschatology map in this year, too.
Eschatology will still require K8Vavoom to run, so be sure to download it if you want to play Eschatology. It will not run in GZDoom.
CL-MeltySynth v2.2.0 and midi123 v1.4.0 are both now out. The notable new features in midi123 are:
- The parallel MIDI rendering that I mentioned before (which is a bit faster now, even). You can do something like "midi123 -s soundfont.sf2 *.mid -n" and it'll just spew out WAV files using as many logical CPU cores as you have. Or you can limit how much it does in paralle with the new --jobs parameter.
- Rendering to different bit depths (16-bit, 24-bit, 32-bit float, 64-bit float... and so on). Playback is always 32-bit float, however, due to a limitation in the cl-portaudio bindings.
- Clozure CL compatibility as an alternative to using SBCL. I don't suggest using Clozure CL to build it, however. Rendering Duke3D's "Stalker" to a WAV takes a SBCL build about 4 seconds, while a Clozure CL build takes about 37 seconds :-P
Also, midi123 is now a separate project in its own repo (linked below). There is a 64-bit Linux AppImage of v1.4.0 available on that link as well if you want a binary. It should work on pretty much any Linux system.
midi123 v1.4.0 announcement and source code: https://chiselapp.com/user/MistressRemilia/repository/midi123/technote/f068eff9dfe188fc9ea3948e17503c7d9d0d6796
CL-MeltySynth v2.2.0 announcement and source code: https://chiselapp.com/user/MistressRemilia/repository/CL-MeltySynth/technote?name=f5996dd68422709e4c80c5d87d47d890160064fa
Awww yeah! :D I just added support for rendering multiple MIDIs in parallel using midi123. It can render the entire Rise of The Triad soundtrack (34 separate MIDI files) to separate WAVs in about 13 seconds.
For the record, rendering these to WAV in serial takes 1 minute 37 seconds on my machine, so... yeah, nice speed improvement by doing stuff in parallel.
Also, some geekier stuff:Spoiler
Up until now, CL-MeltySynth and midi123 both required SBCL, the Common Lisp compiler/implementation I tend to use most often. It's known to be a very good Lisp implementation. But I've also added support for using Clozure CL (that's "Clozure" with a Z, not a J) since I sometimes use it instead of SBCL. Both compile Common Lisp code to native machine code.
Well, adding support for ClozureCL gave me a chance to benchmark the two implementations with actual real-world code, and so I did by rendering "Stalker" from Duke Nukem 3D to a WAV:
- SBCL (cubic interpolation, Zita-Rev1 reverb, soft clipping, TPDF dithering): 4.995071 seconds
- SBCL and using Freeverb: 4.138059 seconds
- SBCL and using Freeverb, no chorus, and linear interpolation: 3.831054 seconds
- Clozure CL (cubic interpolation, Zita-Rev1 reverb, soft clipping, TPDF dithering): 37.679654 seconds
- Clozure CL using Freeverb: 43.52037 seconds
- Clozure CL and using Freeverb, no chorus, and linear interpolation: 41.71585 seconds
- Unfinished Crystal port (Freeverb, no chorus, linear interpolation, no soft clipping, no dithering): ~3.7 seconds
Definitely a larger difference in compiled code speed than I expected :-P
That last one was merely a curiosity since I tend to use Crystal (think "Ruby-inspired, but compiled to native code with LLVM) whenever I don't use Common Lisp. I think I may actually finish my old unfinished Crystal port just because it gives me a really good real-world benchmark to use.
FWIW, FluidSynth tended to take about 2.9-3.2 seconds on my machine for this same file, and it uses something based on Freeverb for its reverb afaik.
Interesting. Never heard about Crystal. I guess programming languages are coders next favorite pet after frameworks. 😏
Crystal is a nice language, quite easy and fun to work with. And their compiler produces really nice native code, it seems. I helped out with the Crystal dependency manager/build tool called Shards not long ago by add Fossil support to it.
My only problem with Crystal is that I'm not sure quite how to fit it into my normal workflow. Crystal seems to be especially good for things like command line programs (which I normally do in Lisp) and web-based programs (which I almost never write, save for Matrix bots). So I haven't really found much benefit in using it over Common Lisp. But I keep hoping I'll find more use for it because damn is it a nice language to work with, and I find its syntax particularly pleasant.
Oddly, Crystal was the language that actually got me interested in Ruby and using it for things like Rakefiles and some other scripting tasks. Most people seem to go the other way, where they were Ruby users first, then became Crystal users.
Heed this warning!
With a drought of sacrifice comes Xala'noth,
Who will again beget the Goat Child.
With terrible strength it destroy those who do not give
And become a symbol of death once again.
The remaining souls, floating in the death,
will be devoured by shapeless Vordessa.
Bludgeoned and mangled between her thousands of teeth.
Then the cursed souls will be thrust
Into the acidic bowels of their new hell,
forever clawing at the flesh until their digits bleed in agony.
And then the Goat Child will die in its mother's smiling grasp,
Sleeping in death, waiting for her call once again.
This is the prophecy of our time.Spoiler
Don't mind me, i had a random idea for some flavor text for my personal mythology I keep reusing in my levels.
- Show previous comments 3 more
As long as you don't know of Xala'noth,
Xala'noth will not know of you.
But those who do not know Xala'noth
will be the first to die.
So wait, are you returning to Eschatology then??
Oh sure, it's definitely going to be finished. I'm just taking a break from mapping for a while to work on other things (though I am getting the itch to start mapping again...)